external authentication login script using c#

I don't know if anybody has already done it, but this is a small script which allows external authentication using C# under windows.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ExternalAuthenticationCSharpScript
{
	class Program
	{
		static void Main(string[] args)
		{
			const int maxbuflen = 1000;		// maximum buffer len
			int read;				// number of bytes read
			char[] charray = new char[maxbuflen];	// buffer
			
			String opcode;				// operation code
			String username;			// username
			String password = "";			// password

			// Read data from stdin
			read = Console.In.Read(charray, 0, 2);
			if (read != 2)
			{
				return;
			}

			// Perform big endian conversion
			int len = charray[1] + (charray[0] * 256);
			// Check for buffer overrun
			if (len > maxbuflen)
			{
				return;
			}

			// Read opcode, username and password
			read = Console.In.ReadBlock(charray, 0, len);
			
			// Splits the data
			string data = new string(charray);
			string[] elements = data.Split(':');

			opcode = elements[0];
			username = elements[1];
			if (elements.Length > 2)
				password = elements[2];

			/*
			 * PERFORM AUTHENTICATION HERE
			 */
			
			// Prepare return value, first short is always 2
			charray[0] = (char)0;
			charray[1] = (char)2;
			
			// Second short is 1 for success, 0 for failure
			charray[2] = (char)0;
			charray[3] = (char)1; // or 0 for failure

			// Send return value
			Console.Out.Write(charray, 0, 4);

			return;
		}
	}
}

not anonymous anymore

Sorry, didn't register to the site before posting. Now I have an account.
fc

I added this page, so people

I added this page, so people can find your example easier: check_csharp

sizeof(char) in .NET is 2.

sizeof(char) in .NET is 2. This code will break if the incoming data is sufficiently large. Use a binary reader to read the correct number of bytes from stdin.

// (this should be outside your while(true) loop)
var stdinStream = Console.OpenStandardInput();
var binReader = new BinaryReader(stdinStream);

// Read data from stdin
var b1 = binReader.ReadByte();
var b2 = binReader.ReadByte();

// Perform big endian conversion
int len = b2 + (b1 * 256);

// Check for buffer overrun
if (len > maxbuflen)
    throw new InternalBufferOverflowException(string.Format("{0} > {1}", len, maxbuflen));
                   
// Read opcode, username and password
var bytes = binReader.ReadBytes(len);
var data = ASCIIEncoding.ASCII.GetString(bytes);
string[] elements = data.Split(':');

// etc etc ...

Just thought I would include

Just thought I would include an example of the two sets of comments combined.

The config is in C:\Program Files (x86)\ejabberd-2.1.1\conf
The file is ejabberd.cfg

%%
%% auth_method: Method used to authenticate the users.
%% The default method is the internal.
%% If you want to use a different method,
%% comment this line and enable the correct ones.
%%
%{auth_method, internal}.

%%
%% Authentication using external script
%% Make sure the script is executable by ejabberd.
%%
{auth_method, external, internal}.
{extauth_program, "c:\\temp\\ConsoleApplication1.exe"}.

FYI - I had issues with spaces in the path and a lack of escaped \ i.e. \\. e.g. I found this failed to work "c:\\Program Files (x86)\\ConsoleApplication1.exe" and left the server running with this error:

** {badarg,[{extauth,call_port,2},
            {ejabberd_auth_external,check_password,3},
            {ejabberd_auth,check_password_loop,2},
            {cyrsasl_plain,mech_step,2},
            {cyrsasl,server_step,2},
            {ejabberd_c2s,wait_for_feature_request,2},
            {gen_fsm,handle_msg,7},
            {proc_lib,init_p,5}]}

Anyhow the code I have working is here:

using System;
using System.IO;
using System.Text;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            const int maxbufferLength = 1000; // maximum buffer len
            var outputMessage = new char[maxbufferLength]; // buffer

            var stdinStream = Console.OpenStandardInput();
            var binaryReader = new BinaryReader(stdinStream);

            while (true)
            {
                // Read data from stdin
                var b1 = binaryReader.ReadByte();
                var b2 = binaryReader.ReadByte();

                // Perform big endian conversion
                var expectedInputLength = b2 + (b1 * 256);

                // Check for buffer overrun
                if (expectedInputLength > maxbufferLength)
                {
                    throw new InternalBufferOverflowException(string.Format("{0} > {1}", expectedInputLength,
                                                                            maxbufferLength));
                }

                // Read opcode, username and password
                var bytes = binaryReader.ReadBytes(expectedInputLength);
                var data = Encoding.ASCII.GetString(bytes);
                var elements = data.Split(':');

                /*
                 * PERFORM AUTHENTICATION HERE
                 */

                // Prepare return value, first short is always 2
                outputMessage[0] = (char)0;
                outputMessage[1] = (char)2;

                // Second short is 1 for success, 0 for failure
                outputMessage[2] = (char)0;
                outputMessage[3] = (char)1; // or 0 for failure

                // Send return value
                Console.Out.Write(outputMessage, 0, 4);
            }
        }
    }
}

Syndicate content