This commit is contained in:
2022-06-20 23:24:10 +00:00
parent 7ced9e377c
commit 0526dab167
5 changed files with 182 additions and 16 deletions

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AyaNovaQBI
{
/// <summary>
/// Authorization roles
/// </summary>
[Flags]
public enum AuthorizationRoles : int
{
//https://stackoverflow.com/questions/8447/what-does-the-flags-enum-attribute-mean-in-c
//MAX 31 (2147483647)!!! or will overflow int and needs to be turned into a long
//Must be a power of two: https://en.wikipedia.org/wiki/Power_of_two
///<summary>No role set</summary>
NoRole = 0,
///<summary>BizAdminRestricted</summary>
BizAdminRestricted = 1,
///<summary>BizAdmin</summary>
BizAdmin = 2,
///<summary>ServiceRestricted</summary>
ServiceRestricted = 4,
///<summary>Service</summary>
Service = 8,
///<summary>InventoryRestricted</summary>
InventoryRestricted = 16,
///<summary>Inventory</summary>
Inventory = 32,
///<summary>Accounting</summary>
Accounting = 64,//No limited role, not sure if there is a need
///<summary>TechRestricted</summary>
TechRestricted = 128,
///<summary>Tech</summary>
Tech = 256,
///<summary>SubContractorRestricted</summary>
SubContractorRestricted = 512, //same as tech but restricted by further business rules (more fine grained)
///<summary>SubContractor</summary>
SubContractor = 1024,//same as tech limited but restricted by further business rules (more fine grained)
///<summary>ClientRestricted</summary>
CustomerRestricted = 2048,
///<summary>Client</summary>
Customer = 4096,
///<summary>OpsAdminRestricted</summary>
OpsAdminRestricted = 8192,
///<summary>OpsAdmin</summary>
OpsAdmin = 16384,
///<summary>Sales</summary>
Sales = 32768,
///<summary>SalesRestricted</summary>
SalesRestricted = 65536,
///<summary>Anyone of any role</summary>
All = BizAdminRestricted | BizAdmin | ServiceRestricted | Service | InventoryRestricted |
Inventory | Accounting | TechRestricted | Tech | SubContractorRestricted |
SubContractor | CustomerRestricted | Customer | OpsAdminRestricted | OpsAdmin | Sales | SalesRestricted
// ,AllInsideUserRoles = BizAdminRestricted | BizAdmin | ServiceRestricted | Service | InventoryRestricted |
// Inventory | Accounting | TechRestricted | Tech | SubContractorRestricted |
// SubContractor | Sales | SalesRestricted | OpsAdminRestricted | OpsAdmin
}//end AuthorizationRoles
}

View File

@@ -75,6 +75,7 @@
<Compile Include="auth.Designer.cs"> <Compile Include="auth.Designer.cs">
<DependentUpon>auth.cs</DependentUpon> <DependentUpon>auth.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="AuthorizationRoles.cs" />
<Compile Include="MainForm.cs"> <Compile Include="MainForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
@@ -91,6 +92,7 @@
<Compile Include="tfa.Designer.cs"> <Compile Include="tfa.Designer.cs">
<DependentUpon>tfa.cs</DependentUpon> <DependentUpon>tfa.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="UserType.cs" />
<Compile Include="util.cs" /> <Compile Include="util.cs" />
<EmbeddedResource Include="auth.resx"> <EmbeddedResource Include="auth.resx">
<DependentUpon>auth.cs</DependentUpon> <DependentUpon>auth.cs</DependentUpon>

20
AyaNovaQBI/UserType.cs Normal file
View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AyaNovaQBI
{
/// <summary>
/// AyaNova User types
/// </summary>
public enum UserType : int
{
Service = 1,
NotService = 2,
Customer = 3,
HeadOffice = 4,
ServiceContractor = 5
}
}

View File

@@ -42,8 +42,7 @@ namespace AyaNovaQBI
{ {
if (!ValidateAndCleanServerAddress()) return; if (!ValidateAndCleanServerAddress()) return;
btnLogin.Enabled = btnTest.Enabled = false; btnLogin.Enabled = btnTest.Enabled = false;
// if (!util.Initialized)
//{
var result = await util.InitAndConfirmAddressAsync(edServerUrl.Text); var result = await util.InitAndConfirmAddressAsync(edServerUrl.Text);
if (result != "OK") if (result != "OK")
{ {
@@ -51,7 +50,8 @@ namespace AyaNovaQBI
btnLogin.Enabled = btnTest.Enabled = true; btnLogin.Enabled = btnTest.Enabled = true;
return; return;
} }
// } try
{
var res = await util.AuthenticateAsync(edUserName.Text, edPassword.Text); var res = await util.AuthenticateAsync(edUserName.Text, edPassword.Text);
if (!res) if (!res)
{ {
@@ -60,6 +60,40 @@ namespace AyaNovaQBI
this.DialogResult = DialogResult.Cancel; this.DialogResult = DialogResult.Cancel;
return; return;
} }
}catch(Exception ex)
{
// ---------------------------
//---------------------------
//Error attempting to login:
// POST error, code: 401, route: auth / tfa - authenticate
//{ "error":{ "code":"2003","message":"ErrorAPI2003"} }
// Unauthorized
// POSTED OBJECT:
// { "pin":"123456","tempToken":"YvIS2IovMIWUYc4NaovwhNcFXviWwEOx4qvpzt8vfQQ"}
// ---------------------------
// OK
// -------------------------- -
MessageBox.Show("Error attempting to login:\r\n" + ex.Message);
this.DialogResult = DialogResult.Cancel;
return;
}
MessageBox.Show($@"TEST - LOGIN SUCCEEDED: \r\
AyaNovaUserName: {util.AyaNovaUserName}\r\n
JWT: {util.JWT}\r\n
AyaNovaUserId: {util.AyaNovaUserId}\r\n
AyaNovaUserTranslationId: {util.AyaNovaUserTranslationId}\r\n
AyaNovaUserRoles: {util.AyaNovaUserRoles}\r\n
AyaNovaUserType: {util.AyaNovaUserType}");
btnLogin.Enabled = btnTest.Enabled = true; btnLogin.Enabled = btnTest.Enabled = true;

View File

@@ -25,6 +25,12 @@ namespace AyaNovaQBI
internal static string GuessClientUrl { get; set; } internal static string GuessClientUrl { get; set; }
internal static string JWT { get; set; } internal static string JWT { get; set; }
internal static long AyaNovaUserId { get; set; }
internal static long AyaNovaUserTranslationId { get; set; }
internal static string AyaNovaUserName { get; set; }
internal static AuthorizationRoles AyaNovaUserRoles { get; set; }
internal static UserType AyaNovaUserType { get; set; }
@@ -92,8 +98,8 @@ namespace AyaNovaQBI
var InnerErr = ""; var InnerErr = "";
if (ex.InnerException != null) if (ex.InnerException != null)
InnerErr = ex.InnerException.Message; InnerErr = ex.InnerException.Message;
return false;
// throw new Exception("POST error, route: " + route + "\r\nError:" + Err + "\r\nInner error:" + InnerErr + "\r\nStack:" + ex.StackTrace + "\r\nPOSTED OBJECT:\r\n" + postJson); throw new Exception("Authentication error, route: AUTH\r\nError:" + Err + "\r\nInner error:" + InnerErr);
} }
//ApiResponse a = await PostAsync("auth", creds.ToString()); //ApiResponse a = await PostAsync("auth", creds.ToString());
@@ -107,30 +113,65 @@ namespace AyaNovaQBI
//Get temp token from response //Get temp token from response
var tempToken = a.ObjectResponse["data"]["tt"].Value<string>(); var tempToken = a.ObjectResponse["data"]["tt"].Value<string>();
string tfaPin = null;
bool keepTrying = true;
//get 2fa code and send it in //get 2fa code and send it in
do do
{ {
tfa t = new tfa(); tfa t = new tfa();
if (t.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) return false; if (t.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) return false;
tfaPin = t.TFAPin; string tfaPin = t.TFAPin;
dynamic tfaCreds = new JObject();
tfaCreds.pin = tfaPin;
tfaCreds.tempToken = tempToken;
try
{
var tfaResponse = await TryPostAsync("auth/tfa-authenticate", tfaCreds.ToString(Newtonsoft.Json.Formatting.None));//trypost is no delay
if (ProcessLoginResponse(tfaResponse)) return true;
}
catch(Exception ex)
{
if (!ex.Message.Contains("2003"))//if not an authentication error (bad pin) then throw it back up for display
throw ex;
//otherwise eat it and let them re-enter the pin again to mirror how ayanova web client works
}
} while (true);
} while (keepTrying);
} }
else else
{ {
JWT = a.ObjectResponse["data"]["token"].Value<string>(); return ProcessLoginResponse(a);
return true;
} }
} }
return false; return false;
} }
private static bool ProcessLoginResponse(ApiResponse a)
{
if (a.ObjectResponse == null) return false;
if (!a.HttpResponse.IsSuccessStatusCode)
{
return false;
}
if(a.ObjectResponse["data"]["l"].Value<bool>())//license lockout
{
throw new Exception("Server login from QBI is disabled due to AyaNova license issue");
}
JWT = a.ObjectResponse["data"]["token"].Value<string>();
// AyaNovaUserId= a.ObjectResponse["data"]["id"].Value<long>();//nbot here maybe in jwt
//AyaNovaUserTranslationId = a.ObjectResponse["data"]["tid"].Value<long>();
AyaNovaUserName = a.ObjectResponse["data"]["name"].Value<string>();
AyaNovaUserRoles = (AuthorizationRoles)(int.Parse(a.ObjectResponse["data"]["roles"].Value<string>()));
AyaNovaUserType = (UserType)(int.Parse(a.ObjectResponse["data"]["usertype"].Value<string>()));
return true;
}
public async static Task<ApiResponse> GetAsync(string route) public async static Task<ApiResponse> GetAsync(string route)