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