How to use Security Provider with a Server Connect Action from another site

Yes, thats what i suggested. When you say didn’t have success, with which aspect?

You should be able to text that server action by calling it locally on your IIS server from app connect.

Is the page on your Apache server calling the IIS server connect action correctly?

Any error messages etc would be a big help

As to == vs ===, as both are 64 char long results I guess it wont make any difference. that was just habit

I think that the Apache configuration should be fine.

I’ll send you the link to both servers via PM.

In addition to Brian’s solution you need to know that IIS is producing upper case characters in the hash and you have to add .lowercase() to the condition:

{{$_GET.token.sha256(‘mysecretsalt’).lowercase() == $_GET.check}}

I had to delete one = because it did not work with 3 =

EDIT: I’m not sure if I was clear. The solution from @Hyperbytes (Post 15) with my changes (this Post) worked perfectly!

@George, @Teodor, @patrick,

is the solution above still the best to secure a Server Connect Action from another site?

If not, what would be the recommended way to go?

Thanks a lot in advance,

Marcel

I am busy looking at this again myself. Basically I am looking to access the data site from the client site by using a server api call. I am looking at a standard auth mechanism where the client is granted an auth token which is then used as an authorisation for further calls. None of the data is massively sensitive, certainly nothing financial so am undecided on a token grant/ expiry system or simply using a token which is encrypted by the client using encrypt with password then decrypted by the data server to check validity with a rotating encryption key. Interested in any comment re this.

I‘m also looking for the solution with a server api call. It has to be very secure in my case because I have financial data which I have to get from our Intranet.

In my case all the data is held on one site, say site1.com

Users use a portal, say site2.com where multiple users access their own dataset on the same site

At the moment I am looking at.

User logins into site2.com using usual username and password which is authenticated by a post api call to site1.com

Site1.com authenticates the login, creates a unique temporary token and sets an expiry time ( i will probably be using about 2 hours) and returns it to site2.com (i will then store it as a cookie)

To assist against injection, site1.com and site2.com will last have a shared cryto key, site2.com will send the login name encryped (using encrypt with Password) using this key as an additional parameter. Site1.com will un-encrypt that and check that the token encrypts to the user name to validate that the call came from the correct place i.e. not injected.

All further access is done with reference to that token, the token is checked against the users, the userid identified and data filtered on that.

I will also be extending the token length to 2 hours from NOW() after each calls so the user will not be rejected in the case of long pauses in use.

If the token expires site1.com will simply return “401 unauthorised” and the user will have to log in again

Can you see any security issues with that?

1 Like

This is similar to my setup.

It looks like a good solution, but I’m not a security expert.

I would be very interested in some screenshots, when you finished your setup.

1 Like

Fingers crossed, 2-3 days max, the relevant site is currently high on my priority list

2 Likes

So here is phase 1 or version 1 of my API , the authentication stage. Can’t believe it was so simple.

Comments/ feedback welcome

NOTE 1 I have not encrypted passwords to keep this tutorial simple however passwords should be encrypted in any deployed situation.

NOTE 2 You may want to set this up without the reversible password encryption until you have defined your schema api schema at the client side or generating the schema is difficult as encrypted parameters will need to be input

We will start with the data hosting site and write then server action.

We will be posting the data from the client site via an AI call using POST

The two sites have a shared key which is used for encrypting / decrypting the login details to add an extra level of security

So let’s define our globals first, the parameters passed are email and password for use as a login

image

In this example the shared key is "@Wappler_Rocks@’

So we start by adding a standard server connection

image

We then add a security provider. to keep things simple i do not have multiple roles defined but this would be possible in the normal way as all security restrictions will be applied at data server level

The security provider defines the fields used for login and the unique user identity to return, in this case SAAID

We now add a standard security login. REMEMBER, the email will be encrypted and will need to be decrypted using the shared key

So the username will be: {$_POST.email.decrypt("@Wappler_Rocks@")}}
and password will be: {{$_POST.password.decrypt("@Wappler_Rocks@")}} or when using password encryption {{$_POST.password.decrypt("@Wappler_Rocks@").sha512(“your_salt”)}} (based on sha512 encryption in this example)

image

Now we generate a random authorisation token. I will do this by encrypting UTC_NOW with a salt and then adding the users Identity as a string to ensure the auth tokens cant be identical if two users perform an API request at exactly the same moment. We set the authkey to output as it will be needed by the client

Now we simple perform a table update to store the auth key and expiry. As I am using sha512 encryption the auth key field should be large enough for the 128 character encryption key plus whatever is needed for the maximum length of the largest ID anticipated to be used.

So we simply insert the key and expiry time into the database table against the current logged in users record. I am using a 2 hour excpiry so the expression will be {{NOW_UTC.dateAdd('hours",2)}}

With the condition

That’s the API server side done!

Now over at client side we have a login form

Input names are email and password

Create you global POST variables

image

We now create an api call to the server

The url is simply the url of the server action on the data server (in my case using php, https://domainname/dmcConnect/api/server_action_name.php

The api call should be set to Method: POST
Data Type: Form

We send the email and password as login credentials but we must encrypt them first with encrypt with Password

so our parameters are
{{$_POST.email.encrypt("@Wappler_Rocks@")}}
and
{{$_POST.password.encrypt("@Wappler_Rocks@")}}

You can define your schema by entering the login details. You did take notice of my note at the start re generating the schema then adding the encryption?

Dont forget to make your form a server connect form and point it at this server action

Now within your form you can accept the authorisation token passed back from the API

On the success event of the login form you can pick up the authkey from the API output and store it by whatever method you want, (i will be using a cookie)

image

Failed logins can be handled in the normal way by using the “Unauthorised” dynamic event of the form

From this point i will be using that key to get the data by passing the key to the API server, where it will be used to filter the data for the user using the condition authkey={{authkey}} AND NOW_UTC < {{expires}}

MORE TO FOLLOW

6 Likes

Hi Brian,

thanks a lot for your great example!

One question. My usernames and passwords are on site2.com (portal). How would you solve this? I thought of synchronizing the usertable to site1.com (only for API access).

Following situation:

site1.com Server Connect API from local CRM/ERP Software / Users are employees

site2.com Portal / Users are customers

site2.com needs access to customer related data from our CRM/ERP Software.

I hope that this makes sense :slight_smile:

I will have a think about that.

My plan was for site 1 to hold all data including login details. New logins would be created by a POST API call

Gut feeling is security will be better with authorisation in one place

Then again, a one off sync of login data initially then extend your registration action to also post the registration logins to site1 with a POST API call

Then you can effectively do an initial login on site2 and also an API login via site1 within your single login action. That way you have a API login credential for APi calls and also a local security provider for page security

1 Like

Hi Brian,

I tried your example yesterday, but didn’t have success. I’m getting a 500 error. I think that it is because security provider is not on the same server and the session is not set on success. Using it on the same server it does work.

How did you solve this?

Sorry Marcel, you will have to give me more info.

What is the 500 error? (set debug mode if not showing)

My process does not rely on sessions, it uses the authorisation token as a substitute for the security provider. How are you using it? I am using my example in a live situation now and it works perfectly

More info please

Sorry for not posting more information :grinning::

That is the 500 error:

{"code":0,"file":"\/usr\/www\/users\/kundenportal\/dmxConnectLib\/modules\/api.php","line":226,"message":"Failed to connect to api.mydomain.de port myport: Connection refused","trace":"#0 \/usr\/www\/users\/kundenportal\/dmxConnectLib\/lib\/App.php(173): modules\\api->send(Object(stdClass), 'api1')\n#1 \/usr\/www\/users\/kundenportal\/dmxConnectLib\/lib\/App.php(107): lib\\App->execSteps(Object(stdClass))\n#2 \/usr\/www\/users\/kundenportal\/dmxConnectLib\/lib\/App.php(72): lib\\App->exec(Object(stdClass))\n#3 \/usr\/www\/users\/kundenportal\/dmxConnect\/api\/API\/Kontoauszug.php(112): lib\\App->define('{\\n \"settings\":...')\n#4 {main}"}

The connection to the server is not the problem as I already use it for an other API Connection.
The server action works without an error if I call it directly on site1.com.

site2.com (php)

image

image

image

site1.com (asp.net)

image

image

Did I oversee something?

So you connection is being refused rather than login failing?

what happens if you simply call the api URL directly in your browser, what is returned by the API?

Can you you PM me a link if it’s not too confidential?

coming late to this but I see ASP.net

Administered by Active Directory Permissions

Is it possible that a different data connection PORT is defined in site2 vs site1?

Or do you need to open port #### for “outgoing access” on the mysql server to that table in site2?

How did you resolve this, please ?

Yes, site1.com is on Port 10445 (it is a local IIS Installation on our intranet) standard Port is taken by another website.
site2.com on Port 443

I just found a solution for my problem.

My API works now like it should!

2 Likes

Hi Brian,
now that I got everything working like in your example, I have a question about your decision using a cookie instead of a server session. I’m interested if there is a specific reason you prefer a cookie over a session?
Thanks a lot in advance!

Simply that a cookie would provide more flexibility in relation to token lifetime I guess.

1 Like