Solved

Get credentials for Acumatica via events

  • 11 January 2022
  • 20 replies
  • 331 views

Userlevel 4
Badge +2

Hi,

I have linked my project with Acumatica in Customization project editor

My solution calls the event

Performs check for Payment and execute some REST requests if the desirable payment is selected.

My question is : How to get Acumatica credentials in project ? When the event is triggered it is already have access to the system, because can check the element’s values, so maybe I can get credentials in code.

Currently I have wrote Acumatica credentials in project for requests like this 

But, client can change them, or make some modifications in Acumatica, so there is must be opportunity to change them without making changes in project solution.

How can I get the credentials for REST request in project ?

icon

Best answer by markusray17 12 January 2022, 20:59

View original

20 replies

Userlevel 7
Badge +11

Hi @Ivan 

I didn't try this before. Can you please try with RSACryptoServiceProvider.Decrypt Method?. Since Acumatica using RSACryptoServiceProvider.
 

Hi, jinin 

I have added Users entity to Acumatica as you suggested 

but the request is unworkable

I tried to find fields named admin and password, but they are absent here 

 

HI @Ivan 

  1. select User Information object
    2. you will get the fields Login and password. 
Userlevel 6
Badge +5

Yeah that is what I was saying, by default Acumatica will hash passwords(using the SHA1 algorithm I believe) and only store the hash. As such you cannot get the actual password. You can get the password hash off the Users object though: Users.PK.Find(graph, userID). 

Basically if you are trying to re-use the current Acumatica username and password in an API call(assuming I am understanding you correctly) that is not an option with you current configuration. Acumatica doesn’t actually know your password in this scenario it just knows the hashed result of your password. So when you type in your password to login Acumatica performs the same hashing function on it and then compares that to the the stored hash result(in the database) to determine if it is the correct password.

You can turn off the hashing but that’s not recommended.

 

It sounds like you are trying to make an API call to Acumatica itself from within graph code which is probably not the best route. If you absolutely have to I would look at other API authorization methods(that don’t involve user passwords). Generally speaking though anything done through the API can be done via internal code. What is it you are trying to accomplish with the API calls?

Userlevel 6
Badge +5

That can all be done via internal code and would be much more performant(and probably easier to code). 

In the event handler you already have access to the payment data but if you need other records you can use BQL statements to retrieve them. If you need to create invoices or apply payments that can all be done via various graphs and methods as well.

Userlevel 6
Badge +5

Acumatica Open University has an Application Development section that covers various topics, there’s also a pdf Acumatica Developer Guide.

 

DocumentsToApply uses the Adjustments view on the graph assuming you are in an extension graph for ARPaymentEntry you should be able to access it with Base.Adjustments.Select();, this will give you all the “DocumentToApply” for the current payment.

 

You can get the customer record by using Customer.PK.Find(customerID);

 

For the third one there are multiple ways to go about it. It seems like you are trying to find all payments(and their pending adjustments) with a certain reference number. I would just write a BQL statement and base it off of the BQL statement used in the Adjustments view(modified to take in parameters). 

 

I would recommend going through the training as most of the above won’t make sense if you aren’t familiar with the framework. 

Userlevel 6
Badge +5

That's why I was suggesting going through the training, you are going to have a lot of questions like that and this thread is going to get very long.

 

Graphs are business logic controllers in Acumatica, you are within an extension of a graph meaning you can access the base graph using the Base property on your extension. So to answer your question, you don't need to create a new graph you just need to pass in "Base"(the base graph). 

Userlevel 7
Badge +11

Hi @Ivan 


We can achieve this by using endpoint entity Users. But still, the password is in an encrypted format. you need to write logic to decrypt and use for this.
 


Hope this will help you.

Userlevel 6
Badge +5

I believe by default Acumatica hashes the passwords which would mean you can’t actually get the original password(the default admin password “setup” is stored in plaintext though).

 

You should be able to get the current User ID using ICurrentUserInformationProvider.GetUserId() and from there you can just use Users.PK.Find(graph, userID) the Users object will have the username and the password hash.

 

If you have disabled password hashing(not recommended) and instead are using encryption you should be able to use IUserManagementService.GetUser(userID) to get the MembershipUser object and then call GetPassword() on that. If password hashing is enabled then it will throw an error. 

 

Below is a short code sample from within a graph.

 

        [InjectDependency]
private ICurrentUserInformationProvider currentUserInformationProvider { get; set; }

[InjectDependency]
private IUserManagementService userManagementService { get; set; }

private Guid? getCurrentUserID()
{
return currentUserInformationProvider.GetUserId();
}

private string GetPassword(Guid userID)
{
return userManagementService.GetUser(userID).GetPassword();
}

 

Userlevel 6
Badge +5

ICurrentUserInformationProvider is in the PX.Data namespace if it isn’t showing up in Intellisense you are likely on an older version, you should be able to just use PXAccess.GetUserID();

Userlevel 7
Badge +11

Hi @Ivan 

I didn't try this before. Can you please try with RSACryptoServiceProvider.Decrypt Method?. Since Acumatica using RSACryptoServiceProvider.
 

Userlevel 4
Badge +2

I believe by default Acumatica hashes the passwords which would mean you can’t actually get the original password(the default admin password “setup” is stored in plaintext though).

 

You should be able to get the current User ID using ICurrentUserInformationProvider.GetUserId() and from there you can just use Users.PK.Find(graph, userID) the Users object will have the username and the password hash.

 

If you have disabled password hashing(not recommended) and instead are using encryption you should be able to use IUserManagementService.GetUser(userID) to get the MembershipUser object and then call GetPassword() on that. If password hashing is enabled then it will throw an error. 

 

Below is a short code sample from within a graph.

 

        [InjectDependency]
private ICurrentUserInformationProvider currentUserInformationProvider { get; set; }

[InjectDependency]
private IUserManagementService userManagementService { get; set; }

private Guid? getCurrentUserID()
{
return currentUserInformationProvider.GetUserId();
}

private string GetPassword(Guid userID)
{
return userManagementService.GetUser(userID).GetPassword();
}

 

I believe by default Acumatica hashes the passwords which would mean you can’t actually get the original password(the default admin password “setup” is stored in plaintext though).

 

You should be able to get the current User ID using ICurrentUserInformationProvider.GetUserId() and from there you can just use Users.PK.Find(graph, userID) the Users object will have the username and the password hash.

 

If you have disabled password hashing(not recommended) and instead are using encryption you should be able to use IUserManagementService.GetUser(userID) to get the MembershipUser object and then call GetPassword() on that. If password hashing is enabled then it will throw an error. 

 

Below is a short code sample from within a graph.

 

        [InjectDependency]
private ICurrentUserInformationProvider currentUserInformationProvider { get; set; }

[InjectDependency]
private IUserManagementService userManagementService { get; set; }

private Guid? getCurrentUserID()
{
return currentUserInformationProvider.GetUserId();
}

private string GetPassword(Guid userID)
{
return userManagementService.GetUser(userID).GetPassword();
}

 

Hi, markusray17

Thank you for response.

Can you please suggest what namespace must be added in order to use ICurrentUserInformationProvider and IUserManagementService ? Intellisense does not suggest me anything.

 

Userlevel 4
Badge +2

Hi @Ivan 

I didn't try this before. Can you please try with RSACryptoServiceProvider.Decrypt Method?. Since Acumatica using RSACryptoServiceProvider.
 

Hi, jinin 

I have added Users entity to Acumatica as you suggested 

but the request is unworkable

I tried to find fields named admin and password, but they are absent here 

 

Userlevel 4
Badge +2

ICurrentUserInformationProvider is in the PX.Data namespace if it isn’t showing up in Intellisense you are likely on an older version, you should be able to just use PXAccess.GetUserID();

I added PX,Data . Now the types are available for usage

However the last string receive the error

It required PX.Export

After I added it to project the error was removed

After I started project I received this error : 
Can't restore password for MembershipPasswordFormat.Hashed password format

Userlevel 4
Badge +2

Hi @Ivan 

I didn't try this before. Can you please try with RSACryptoServiceProvider.Decrypt Method?. Since Acumatica using RSACryptoServiceProvider.
 

Hi, jinin 

I have added Users entity to Acumatica as you suggested 

but the request is unworkable

I tried to find fields named admin and password, but they are absent here 

 

HI @Ivan 

  1. select User Information object
    2. you will get the fields Login and password. 

Thanks , it worked.

Is it possible to extract URL by same approach ?

Userlevel 4
Badge +2

Yeah that is what I was saying, by default Acumatica will hash passwords(using the SHA1 algorithm I believe) and only store the hash. As such you cannot get the actual password. You can get the password hash off the Users object though: Users.PK.Find(graph, userID). 

Basically if you are trying to re-use the current Acumatica username and password in an API call(assuming I am understanding you correctly) that is not an option with you current configuration. Acumatica doesn’t actually know your password in this scenario it just knows the hashed result of your password. So when you type in your password to login Acumatica performs the same hashing function on it and then compares that to the the stored hash result(in the database) to determine if it is the correct password.

You can turn off the hashing but that’s not recommended.

 

It sounds like you are trying to make an API call to Acumatica itself from within graph code which is probably not the best route. If you absolutely have to I would look at other API authorization methods(that don’t involve user passwords). Generally speaking though anything done through the API can be done via internal code. What is it you are trying to accomplish with the API calls?

I need to do API calls in order to extract data from different entities. When the user saves the payment in Acumatica, my solution creates documents on local machine with this payment, invoices which are located in “Document to Apply tab and Customer entity data.”. I use API calls in order to make link between entities and provide valid data.

You understood me correctly, I need to re-use password in order to omit writing credentials inside the project, because they can be changed, that is the reason why I need to get login, password, Url and company in order to build request and make call to other entities inside the event 

Userlevel 4
Badge +2

Hi @Ivan 

I didn't try this before. Can you please try with RSACryptoServiceProvider.Decrypt Method?. Since Acumatica using RSACryptoServiceProvider.
 

Hi, jinin 

I have added Users entity to Acumatica as you suggested 

but the request is unworkable

I tried to find fields named admin and password, but they are absent here 

 

HI @Ivan 

  1. select User Information object
    2. you will get the fields Login and password. 

I tried to decrypt password, by this approach 

 RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();

  byte[] decryptedData;
   decryptedData = RSAalg.Decrypt(credits?.Password?.value, false);

where “credits” variable is the result of REST request and contains credential data

Unfortunately it gives error 

The best overloaded method match for 'System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(byte[], bool)' has some invalid arguments

Userlevel 4
Badge +2

That can all be done via internal code and would be much more performant(and probably easier to code). 

In the event handler you already have access to the payment data but if you need other records you can use BQL statements to retrieve them. If you need to create invoices or apply payments that can all be done via various graphs and methods as well.

Can you please provide reference where it is shown how build such logic ?

I need to implement this for the following requests : 

  1. GET http://10.0.3.100/AcumaticaDB_new/entity/Artsyl20.200.001/Payment/{paymType}/{paymNo}?$expand=DocumentsToApply
  2. GET  http://10.0.3.100/AcumaticaDB_new/entity/Artsyl/20.200.001/Customer/{custId}
  3. GET  http://10.0.3.100/AcumaticaDB_new/entity/Artsyl/20.200.001/Payment?$filter=ReferenceNbr eq '" + paymNo + "'&$expand=DocumentsToApply

Now it works this way :  getRequest = $"http://10.0.3.100/AcumaticaDB_new/entity/Artsyl20.200.001/Payment/{paymType}/{paymNo}?$expand=DocumentsToApply";
                                response = CreateApiCall(client, HttpMethod.Get, true, getRequest, "");
                                payment = JsonConvert.DeserializeObject(message);

And from payment object I retrieve table data 

 

Userlevel 4
Badge +2

Acumatica Open University has an Application Development section that covers various topics, there’s also a pdf Acumatica Developer Guide.

 

DocumentsToApply uses the Adjustments view on the graph assuming you are in an extension graph for ARPaymentEntry you should be able to access it with Base.Adjustments.Select();, this will give you all the “DocumentToApply” for the current payment.

 

You can get the customer record by using Customer.PK.Find(customerID);

 

For the third one there are multiple ways to go about it. It seems like you are trying to find all payments(and their pending adjustments) with a certain reference number. I would just write a BQL statement and base it off of the BQL statement used in the Adjustments view(modified to take in parameters). 

 

I would recommend going through the training as most of the above won’t make sense if you aren’t familiar with the framework. 

Hi markusray17

I am trying to extract elements from Base.Adjustments.Select();,

but I can’t find what must be added for StandAlone.ARRegistertAlias type

Can you please suggest what should be added to the project ?

Userlevel 4
Badge +2

Acumatica Open University has an Application Development section that covers various topics, there’s also a pdf Acumatica Developer Guide.

 

DocumentsToApply uses the Adjustments view on the graph assuming you are in an extension graph for ARPaymentEntry you should be able to access it with Base.Adjustments.Select();, this will give you all the “DocumentToApply” for the current payment.

 

You can get the customer record by using Customer.PK.Find(customerID);

 

For the third one there are multiple ways to go about it. It seems like you are trying to find all payments(and their pending adjustments) with a certain reference number. I would just write a BQL statement and base it off of the BQL statement used in the Adjustments view(modified to take in parameters). 

 

I would recommend going through the training as most of the above won’t make sense if you aren’t familiar with the framework. 

Hi markusray17

I found how to extract elements form Documents To Apply tab (I wrote about this in previous comment)

Now it remains to get the customer record. You suggested to use this : Customer.PK.Find(customerID);

It requires the graph parameter 

I do not know what must be putted here. I can create just object of this type and put it here or it must be initialized and contain some specific data ?

Userlevel 4
Badge +2

That's why I was suggesting going through the training, you are going to have a lot of questions like that and this thread is going to get very long.

 

Graphs are business logic controllers in Acumatica, you are within an extension of a graph meaning you can access the base graph using the Base property on your extension. So to answer your question, you don't need to create a new graph you just need to pass in "Base"(the base graph). 

Thank you for response

I understand that going  through the training is important to omit lost of stages, but I need to finish it as soon as possible

Userlevel 4
Badge +2

Hi @Ivan 


We can achieve this by using endpoint entity Users. But still, the password is in an encrypted format. you need to write logic to decrypt and use for this.
 


Hope this will help you.

Hi, jinin

Thank you for response

I need to clarify one moment : “the password is in an encrypted format. you need to write logic to decrypt and use for this.”

By which approach the password can be decrypted ? It can be done by standard .NET tools or it must be done by specific way ?

Reply


About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved