private bool AuthenticateInboundAdobe(BaseRTMPProtocol pFrom, AmfMessage request, Variant authState)
{
if (authState["stage"] == null) authState["stage"] = "inProgress";
else if (authState["stage"] == "authenticated") return true;
if (authState["stage"] != "inProgress")
{
Logger.FATAL("This protocol in not in the authenticating mode");
return false;
}
//1. Validate the type of request
if (request.MessageType != Defines.RM_HEADER_MESSAGETYPE_INVOKE)
{
this.Log().Info("This is not an invoke. Wait for it...");
return true;
}
//2. Validate the invoke function name
if (request.InvokeFunction != Defines.RM_INVOKE_FUNCTION_CONNECT)
{
Logger.FATAL("This is not a connect invoke");
return false;
}
//3. Pick up the first param in the invoke
Variant connectParams = request.InvokeParam[0];
if (connectParams != VariantType.Map)
{
Logger.FATAL("first invoke param must be a map");
return false;
}
//4. pick up the agent name
if ((connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_FLASHVER] == null)
|| (connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_FLASHVER] != VariantType.String))
{
Logger.WARN("Incorrect user agent");
authState["stage"] = "authenticated";
authState["canPublish"] = false;
authState["canOverrideStreamName"] = false;
return true;
}
string flashVer = connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_FLASHVER];
//6. test the flash ver against the allowed encoder agents
if (_adobeAuthSettings[Defines.CONF_APPLICATION_AUTH_ENCODER_AGENTS, flashVer] == null)
{
Logger.WARN("This agent is not on the list of allowed encoders: `{0}`", flashVer);
authState["stage"] = "authenticated";
authState["canPublish"] = false;
authState["canOverrideStreamName"] = false;
return true;
}
//7. pick up the tcUrl from the first param
if ((connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_APP] == null)
|| (connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_APP] != VariantType.String))
{
Logger.WARN("Incorrect app url");
authState["stage"] = "authenticated";
authState["canPublish"] = (bool)false;
authState["canOverrideStreamName"] = (bool)false;
return true;
}
string appUrl = connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_APP];
//8. Split the URI into parts
var appUrlParts = appUrl.Split('?');
if (appUrlParts.Length == 1)
{
//bare request. We need to tell him that he needs auth
if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeConnectError(request,
"[ AccessManager.Reject ] : [ code=403 need auth; authmod=adobe ] : ")))
{
Logger.FATAL("Unable to send message");
return false;
}
if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeClose()))
{
Logger.FATAL("Unable to send message");
return false;
}
//pFrom.SendMessagesBlock.TriggerBatch();
pFrom.EnqueueForOutbound(pFrom.OutputBuffer);
pFrom.GracefullyEnqueueForDelete();
return true;
}
else if (appUrlParts.Length == 2)
{
var _params = appUrlParts[1].GetURLParam();
if ((!_params.ContainsKey("authmod")) || (!_params.ContainsKey("user")))
{
Logger.WARN("Invalid appUrl: {0}", appUrl);
authState["stage"] = "authenticated";
authState["canPublish"] = false;
authState["canOverrideStreamName"] = false;
return true;
}
string user = _params["user"];
if (_params.ContainsKey("challenge")
&& _params.ContainsKey("response")
&& _params.ContainsKey("opaque"))
{
string challenge = _params["challenge"];
string response = _params["response"];
string opaque = _params["opaque"];
string password = GetAuthPassword(user);
if (password == "")
{
Logger.WARN("No such user: `{0}`", user);
if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeConnectError(request,
"[ AccessManager.Reject ] : [ authmod=adobe ] : ?reason=authfailed&opaque=vgoAAA==")))
{
Logger.FATAL("Unable to send message");
return false;
}
if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeClose()))
{
Logger.FATAL("Unable to send message");
return false;
}
//pFrom.SendMessagesBlock.TriggerBatch();
pFrom.EnqueueForOutbound(pFrom.OutputBuffer);
pFrom.GracefullyEnqueueForDelete();
return true;
}
var md5 = MD5.Create();
string str1 = user + _adobeAuthSalt + password;
string hash1 = Convert.ToBase64String(md5.ComputeHash(Encoding.ASCII.GetBytes(str1)));
string str2 = hash1 + opaque + challenge;
string wanted = Convert.ToBase64String(md5.ComputeHash(Encoding.ASCII.GetBytes(str2)));
if (response == wanted)
{
authState["stage"] = "authenticated";
authState["canPublish"] = true;
authState["canOverrideStreamName"] = true;
Logger.WARN("User `{0}` authenticated", user);
return true;
}
else
{
Logger.WARN("Invalid password for user `{0}`", user);
if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeConnectError(request,
"[ AccessManager.Reject ] : [ authmod=adobe ] : ?reason=authfailed&opaque=vgoAAA==")))
{
Logger.FATAL("Unable to send message");
return false;
}
if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeClose()))
{
Logger.FATAL("Unable to send message");
return false;
}
//pFrom.SendMessagesBlock.TriggerBatch();
pFrom.EnqueueForOutbound(pFrom.OutputBuffer);
pFrom.GracefullyEnqueueForDelete();
return true;
}
}
else
{
string challenge = Utils.GenerateRandomString(6) + "==";
string opaque = challenge;
string description =
"[ AccessManager.Reject ] : [ authmod=adobe ] : ?reason=needauth&user={0}&salt={1}&challenge={2}&opaque={3}";
description = string.Format(description, user, _adobeAuthSalt, challenge, opaque);
if (!pFrom.SendMessage(ConnectionMessageFactory.GetInvokeConnectError(request, description)))
{
Logger.FATAL("Unable to send message");
return false;
}
if (!pFrom.SendMessage(ConnectionMessageFactory.GetInvokeClose()))
{
Logger.FATAL("Unable to send message");
return false;
}
//pFrom.SendMessagesBlock.TriggerBatch();
pFrom.EnqueueForOutbound(pFrom.OutputBuffer);
pFrom.GracefullyEnqueueForDelete();
return true;
}
}
else
{
Logger.FATAL("Invalid appUrl: {0}", appUrl);
return false;
}
}