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);
}
}
}
}