using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace S22.Sasl.Mechanisms { /// /// Implements the Sasl Plain authentication method as described in /// RFC 4616. /// internal class SaslPlain : SaslMechanism { bool Completed = false; /// /// Sasl Plain just sends one initial response. /// public override bool HasInitial { get { return true; } } /// /// True if the authentication exchange between client and server /// has been completed. /// public override bool IsCompleted { get { return Completed; } } /// /// The IANA name for the Plain authentication mechanism as described /// in RFC 4616. /// public override string Name { get { return "PLAIN"; } } /// /// The username to authenticate with. /// string Username { get { return Properties.ContainsKey("Username") ? Properties["Username"] as string : null; } set { Properties["Username"] = value; } } /// /// The plain-text password to authenticate with. /// string Password { get { return Properties.ContainsKey("Password") ? Properties["Password"] as string : null; } set { Properties["Password"] = value; } } /// /// Private constructor for use with Sasl.SaslFactory. /// private SaslPlain() { // Nothing to do here. } /// /// Creates and initializes a new instance of the SaslPlain class /// using the specified username and password. /// /// The username to authenticate with. /// The plaintext password to authenticate /// with. /// Thrown if the username /// or the password parameter is null. /// Thrown if the username /// parameter is empty. public SaslPlain(string username, string password) { username.ThrowIfNull("username"); if (username == String.Empty) throw new ArgumentException("The username must not be empty."); password.ThrowIfNull("password"); Username = username; Password = password; } /// /// Computes the client response for a plain-challenge. /// /// The challenge sent by the server. For the /// "plain" mechanism this will usually be empty. /// The response for the "plain"-challenge. /// Thrown if the response could not /// be computed. protected override byte[] ComputeResponse(byte[] challenge) { // Precondition: Ensure username and password are not null and // username is not empty. if (String.IsNullOrEmpty(Username) || Password == null) { throw new SaslException("The username must not be null or empty and " + "the password must not be null."); } // Sasl Plain does not involve another roundtrip. Completed = true; // Username and password are delimited by a NUL (U+0000) character // and the response shall be encoded as UTF-8. return Encoding.UTF8.GetBytes("\0" + Username + "\0" + Password); } } }