DF 2.4.1 Add extra information upon open registration

Hi,

I have written a little server side script for user.register.post.post_process event that supposedly has to add some extra information that exists in the payload for this particular user in user_custom.

When I execute the /user/register through the API Docs (while logged in as admin) it works without problems. When this gets executed through my mobile application I get the following error in DF’s log:

local.ERROR: Exception: GET access to component ‘user’ of service ‘system’ is not allowed by this user’s role. {“response”:"[object] (DreamFactory\Core\Utility\ServiceResponse: {})"}

What I also have done is that I have created a role called openRegistration and I have given access to

Service: System
Component: user/
Access: GET, PATCH
Requester: SCRIPT

and I have assigned this role to User Service to be given to as Default Open Reg Role and it is actually assigned to self registered user but the script is not able to complete.

Any idea why is this happening or in any case how can I store this extra information upon registration?

Thanks,
George

I have the same problem here: Script Only Working from API Docs

I even made an entire API key with specific access to system/user and my GET call uses that key. I never got it to work outside of admin login and no one had any answers. I had to abandon it.

After having spent more than 20 hours on trying to solve the issue (oh my gosh I don’t believe that I did that!) I think I have come with something that seems that it may work,

My case is that I want to support open registration with confirmation by a client app (i.e. mobile) and while user is registered I want to be able to save some extra information that gets sent over with the registration payload i.e. father name.

Here is what I’ve done and I was able to save into user custom table of DF.

I created a role called “openRegistartion” with access to the following services :

Service: System
Component: user/
Access: GET
Requester: API

Service: System
Component: user/*
Access: PATCH
Requester: API

Then I created an App let’s call it “RegAccessServices” and assigned to it the “openRegistartion” as default role and the App Location set to No Storage Required. I got the API key for the application and then I’ve written the following V8js script in user.register.post.post_process :

if (event.response.status_code == 200) {

var email = event.request.payload.email;

var url = 'http://127.0.0.1/api/v2/system/user';
url = url + "?api_key=11111111111111111111111111111&fields=id&filter="+encodeURIComponent("email="+email);

var result = platform.api.get(url);

var id = result.content.resource[0].id;

var fathername = event.request.payload.fathername;
var payload = JSON.stringify({
“user_custom_by_user_id”: [{
“name”: “fathername”,
“value”: fathername
}]
});

var options = {
    'headers': {
        'Content-Type': 'application/json'
    }
};

var result = platform.api.patch("http://127.0.0.1/api/v2/system/user/"+id+"?api_key=11111111111111111111111111111", payload, options);

}

and it works!

Issues that I don’t like with the above solution :

  • I was not able to call platform.api.patch(“system/user/{id}”) no matter what permissions I gave to the role!!!
  • By giving access to API as requester I have opened a potential back door for tampering with my data by malicious external API calls. The only thing that eases my worries a bit is the api key that is never revealed to the public.

I hope and I would greatly appreciate it if somebody from DF will answer why I can’t use the internal call to platform.api and give some guidance on how to use the internal call format thus I could remove the vulnerability of exposing something that it’s not supposed to!

UPDATE!!

Sometimes I feel like “Lucky Luke” the European cowboy known as the “man who shoots faster than his shadow!” especially when I’m able to answer my own questions before somebody that I believe is more experienced than me (and that’s why I’m crying out for help) does.

I believe that I’ve finally nailed it and found a solution of calling the internal platform.api url and securing my application from the outside world. Here it goes.

Like before create a role “openRegistration” with only SCRIPT Access

Service: System
Component: user/
Access: GET
Requester: SCRIPT

Service: System
Component: user/*
Access: PATCH
Requester: SCRIPT

Create the App like in my previous post and get the API key.

Write the V8js script in user.register.post.post_process :

if (event.response.status_code == 200) {

var email = event.request.payload.email;

var url = 'system/user';
url = url + "?fields=id&filter="+encodeURIComponent("email="+email);


var result = platform.api.get(url);

var id = result.content.resource[0].id;

var fathername = event.request.payload.fathername;
var payload = {

    "user_custom_by_user_id": [{
        "name": "fathername",
        "value": fathername
    }]

};

var options = {
    'headers': {
        'Content-Type': 'application/json'
    }
};

var result = platform.api.patch("system/user/"+id+"", payload, options);

}

and the trick is to include the API KEY of your App in your actual application that does the user registration like the following :

http://{yourDFserver}/api/v2/user/register?api_key=11111111111111111111111111111

where {yourDFserver} is the domain where your DF installation is hosted.

That’s it.

2 Likes

Please see below my latest suggested solution and I think it will help you solve the problem!

1 Like

So your mobile app has to include the special API key that has only script access to system/user?

That seems like a bug to me because basically what you are saying is that the script can’t make an internal API call with a different key than whatever triggered the event. Now I would really like a DF person to comment on this. Maybe @formerstaff ?

You’re right. It seems that the internal calls happen in the context of whatever app/user called them, thus inheriting their rights and privileges.

I can’t decide if this is a bug, but honestly I would prefer if we could somehow be able to perform the operations by specifying the context that the call is to be executed. Maybe there is a way to do that, but unfortunately don’t know it!

You are able to to change headers and parameters in calls made within a script. There was some buggy behavior around this previously, but changing headers has been supported for a while, and changing parameters via the platform object (rather than manually changing them in the request url) was added in 2.4
See the scripting documentation: Scripting: The Platform Resource for details.
Additionally, you can see this blog/script I wrote that actually uses these items here: Database Table Endpoint Obfuscation Through Custom Scripting

@formerstaff

Thanks for the hints and I looked into your suggested links but unfortunately the call to platform.api.patch(“system/user/{id}”) is not working while in user.register.post.post_process event no matter what. The only way to get it working is through my above suggested solution that includes the API key of the application in the original API call.

I suspect that it has to do with the fact that the user is not logged in yet (since I’m using open registration with confirmation), thus, the internal call to “system/user/{id}” is not working because of missing authorization.