292 lines
9.5 KiB
C#
292 lines
9.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Unosquare.Swan.Networking.Ldap {
|
|
/// <summary>
|
|
/// The class performs token processing from strings.
|
|
/// </summary>
|
|
internal class Tokenizer {
|
|
// The tokenizer uses the default delimiter set: the space character, the tab character, the newline character, and the carriage-return character
|
|
private readonly String _delimiters = " \t\n\r";
|
|
|
|
private readonly Boolean _returnDelims;
|
|
|
|
private List<String> _elements;
|
|
|
|
private String _source;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="Tokenizer" /> class.
|
|
/// Initializes a new class instance with a specified string to process
|
|
/// and the specified token delimiters to use.
|
|
/// </summary>
|
|
/// <param name="source">String to tokenize.</param>
|
|
/// <param name="delimiters">String containing the delimiters.</param>
|
|
/// <param name="retDel">if set to <c>true</c> [ret delete].</param>
|
|
public Tokenizer(String source, String delimiters, Boolean retDel = false) {
|
|
this._elements = new List<String>();
|
|
this._delimiters = delimiters ?? this._delimiters;
|
|
this._source = source;
|
|
this._returnDelims = retDel;
|
|
if(this._returnDelims) {
|
|
this.Tokenize();
|
|
} else {
|
|
this._elements.AddRange(source.Split(this._delimiters.ToCharArray()));
|
|
}
|
|
|
|
this.RemoveEmptyStrings();
|
|
}
|
|
|
|
public Int32 Count => this._elements.Count;
|
|
|
|
public Boolean HasMoreTokens() => this._elements.Count > 0;
|
|
|
|
public String NextToken() {
|
|
if(this._source == String.Empty) {
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
String result;
|
|
if(this._returnDelims) {
|
|
this.RemoveEmptyStrings();
|
|
result = this._elements[0];
|
|
this._elements.RemoveAt(0);
|
|
return result;
|
|
}
|
|
|
|
this._elements = new List<String>();
|
|
this._elements.AddRange(this._source.Split(this._delimiters.ToCharArray()));
|
|
this.RemoveEmptyStrings();
|
|
result = this._elements[0];
|
|
this._elements.RemoveAt(0);
|
|
this._source = this._source.Remove(this._source.IndexOf(result, StringComparison.Ordinal), result.Length);
|
|
this._source = this._source.TrimStart(this._delimiters.ToCharArray());
|
|
return result;
|
|
}
|
|
|
|
private void RemoveEmptyStrings() {
|
|
for(Int32 index = 0; index < this._elements.Count; index++) {
|
|
if(this._elements[index] != String.Empty) {
|
|
continue;
|
|
}
|
|
|
|
this._elements.RemoveAt(index);
|
|
index--;
|
|
}
|
|
}
|
|
|
|
private void Tokenize() {
|
|
String tempstr = this._source;
|
|
if(tempstr.IndexOfAny(this._delimiters.ToCharArray()) < 0 && tempstr.Length > 0) {
|
|
this._elements.Add(tempstr);
|
|
} else if(tempstr.IndexOfAny(this._delimiters.ToCharArray()) < 0 && tempstr.Length <= 0) {
|
|
return;
|
|
}
|
|
|
|
while(tempstr.IndexOfAny(this._delimiters.ToCharArray()) >= 0) {
|
|
if(tempstr.IndexOfAny(this._delimiters.ToCharArray()) == 0) {
|
|
if(tempstr.Length > 1) {
|
|
this._elements.Add(tempstr.Substring(0, 1));
|
|
tempstr = tempstr.Substring(1);
|
|
} else {
|
|
tempstr = String.Empty;
|
|
}
|
|
} else {
|
|
String toks = tempstr.Substring(0, tempstr.IndexOfAny(this._delimiters.ToCharArray()));
|
|
this._elements.Add(toks);
|
|
this._elements.Add(tempstr.Substring(toks.Length, 1));
|
|
|
|
tempstr = tempstr.Length > toks.Length + 1 ? tempstr.Substring(toks.Length + 1) : String.Empty;
|
|
}
|
|
}
|
|
|
|
if(tempstr.Length > 0) {
|
|
this._elements.Add(tempstr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an Ldap Matching Rule Assertion.
|
|
/// <pre>
|
|
/// MatchingRuleAssertion ::= SEQUENCE {
|
|
/// matchingRule [1] MatchingRuleId OPTIONAL,
|
|
/// type [2] AttributeDescription OPTIONAL,
|
|
/// matchValue [3] AssertionValue,
|
|
/// dnAttributes [4] BOOLEAN DEFAULT FALSE }
|
|
/// </pre></summary>
|
|
/// <seealso cref="Unosquare.Swan.Networking.Ldap.Asn1Sequence" />
|
|
internal class RfcMatchingRuleAssertion : Asn1Sequence {
|
|
public RfcMatchingRuleAssertion(
|
|
String matchingRule,
|
|
String type,
|
|
SByte[] matchValue,
|
|
Asn1Boolean dnAttributes = null)
|
|
: base(4) {
|
|
if(matchingRule != null) {
|
|
this.Add(new Asn1Tagged(new Asn1Identifier(1), new Asn1OctetString(matchingRule), false));
|
|
}
|
|
|
|
if(type != null) {
|
|
this.Add(new Asn1Tagged(new Asn1Identifier(2), new Asn1OctetString(type), false));
|
|
}
|
|
|
|
this.Add(new Asn1Tagged(new Asn1Identifier(3), new Asn1OctetString(matchValue), false));
|
|
|
|
// if dnAttributes if false, that is the default value and we must not
|
|
// encode it. (See RFC 2251 5.1 number 4)
|
|
if(dnAttributes != null && dnAttributes.BooleanValue()) {
|
|
this.Add(new Asn1Tagged(new Asn1Identifier(4), dnAttributes, false));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The AttributeDescriptionList is used to list attributes to be returned in
|
|
/// a search request.
|
|
/// <pre>
|
|
/// AttributeDescriptionList ::= SEQUENCE OF
|
|
/// AttributeDescription
|
|
/// </pre></summary>
|
|
/// <seealso cref="Unosquare.Swan.Networking.Ldap.Asn1SequenceOf" />
|
|
internal class RfcAttributeDescriptionList : Asn1SequenceOf {
|
|
public RfcAttributeDescriptionList(String[] attrs)
|
|
: base(attrs?.Length ?? 0) {
|
|
if(attrs == null) {
|
|
return;
|
|
}
|
|
|
|
foreach(String attr in attrs) {
|
|
this.Add(attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an Ldap Search Request.
|
|
/// <pre>
|
|
/// SearchRequest ::= [APPLICATION 3] SEQUENCE {
|
|
/// baseObject LdapDN,
|
|
/// scope ENUMERATED {
|
|
/// baseObject (0),
|
|
/// singleLevel (1),
|
|
/// wholeSubtree (2) },
|
|
/// derefAliases ENUMERATED {
|
|
/// neverDerefAliases (0),
|
|
/// derefInSearching (1),
|
|
/// derefFindingBaseObj (2),
|
|
/// derefAlways (3) },
|
|
/// sizeLimit INTEGER (0 .. maxInt),
|
|
/// timeLimit INTEGER (0 .. maxInt),
|
|
/// typesOnly BOOLEAN,
|
|
/// filter Filter,
|
|
/// attributes AttributeDescriptionList }
|
|
/// </pre>
|
|
/// </summary>
|
|
/// <seealso cref="Unosquare.Swan.Networking.Ldap.Asn1Sequence" />
|
|
/// <seealso cref="Unosquare.Swan.Networking.Ldap.IRfcRequest" />
|
|
internal class RfcSearchRequest : Asn1Sequence, IRfcRequest {
|
|
public RfcSearchRequest(
|
|
String basePath,
|
|
LdapScope scope,
|
|
Int32 derefAliases,
|
|
Int32 sizeLimit,
|
|
Int32 timeLimit,
|
|
Boolean typesOnly,
|
|
String filter,
|
|
String[] attributes)
|
|
: base(8) {
|
|
this.Add(basePath);
|
|
this.Add(new Asn1Enumerated(scope));
|
|
this.Add(new Asn1Enumerated(derefAliases));
|
|
this.Add(new Asn1Integer(sizeLimit));
|
|
this.Add(new Asn1Integer(timeLimit));
|
|
this.Add(new Asn1Boolean(typesOnly));
|
|
this.Add(new RfcFilter(filter));
|
|
this.Add(new RfcAttributeDescriptionList(attributes));
|
|
}
|
|
|
|
public override Asn1Identifier GetIdentifier() => new Asn1Identifier(LdapOperation.SearchRequest);
|
|
|
|
public String GetRequestDN() => ((Asn1OctetString)this.Get(0)).StringValue();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an Ldap Substring Filter.
|
|
/// <pre>
|
|
/// SubstringFilter ::= SEQUENCE {
|
|
/// type AttributeDescription,
|
|
/// -- at least one must be present
|
|
/// substrings SEQUENCE OF CHOICE {
|
|
/// initial [0] LdapString,
|
|
/// any [1] LdapString,
|
|
/// final [2] LdapString } }
|
|
/// </pre>
|
|
/// </summary>
|
|
/// <seealso cref="Unosquare.Swan.Networking.Ldap.Asn1Sequence" />
|
|
internal class RfcSubstringFilter : Asn1Sequence {
|
|
public RfcSubstringFilter(String type, Asn1Object substrings)
|
|
: base(2) {
|
|
this.Add(type);
|
|
this.Add(substrings);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an Ldap Attribute Value Assertion.
|
|
/// <pre>
|
|
/// AttributeValueAssertion ::= SEQUENCE {
|
|
/// attributeDesc AttributeDescription,
|
|
/// assertionValue AssertionValue }
|
|
/// </pre>
|
|
/// </summary>
|
|
/// <seealso cref="Unosquare.Swan.Networking.Ldap.Asn1Sequence" />
|
|
internal class RfcAttributeValueAssertion : Asn1Sequence {
|
|
public RfcAttributeValueAssertion(String ad, SByte[] av)
|
|
: base(2) {
|
|
this.Add(ad);
|
|
this.Add(new Asn1OctetString(av));
|
|
}
|
|
|
|
public String AttributeDescription => ((Asn1OctetString)this.Get(0)).StringValue();
|
|
|
|
public SByte[] AssertionValue => ((Asn1OctetString)this.Get(1)).ByteValue();
|
|
}
|
|
|
|
/// <summary> Encapsulates an Ldap Bind properties.</summary>
|
|
internal class BindProperties {
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="BindProperties" /> class.
|
|
/// </summary>
|
|
/// <param name="version">The version.</param>
|
|
/// <param name="dn">The dn.</param>
|
|
/// <param name="method">The method.</param>
|
|
/// <param name="anonymous">if set to <c>true</c> [anonymous].</param>
|
|
public BindProperties(
|
|
Int32 version,
|
|
String dn,
|
|
String method,
|
|
Boolean anonymous) {
|
|
this.ProtocolVersion = version;
|
|
this.AuthenticationDN = dn;
|
|
this.AuthenticationMethod = method;
|
|
this.Anonymous = anonymous;
|
|
}
|
|
|
|
public Int32 ProtocolVersion {
|
|
get;
|
|
}
|
|
|
|
public String AuthenticationDN {
|
|
get;
|
|
}
|
|
|
|
public String AuthenticationMethod {
|
|
get;
|
|
}
|
|
|
|
public Boolean Anonymous {
|
|
get;
|
|
}
|
|
}
|
|
} |