Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 2.2.24 and above breaks Parse.File.save() - unauthorized #3179

Closed
MartinHerman opened this issue Dec 5, 2016 · 39 comments
Closed

Version 2.2.24 and above breaks Parse.File.save() - unauthorized #3179

MartinHerman opened this issue Dec 5, 2016 · 39 comments

Comments

@MartinHerman
Copy link

MartinHerman commented Dec 5, 2016

Hi everyone,
I think the the recent changes in v2.2.24 regarding "Better support for checking application and client keys" have broken the save() method for saving Parse.Files.

This is very likely related to my other issue #3051, which I think has since been resolved in v2.2.25.

This code worked in v2.2.23 and below:

//Getting Logo Image from Parse.Cloud.httpRequest
var logoFilename = "logo.png";
var logoFile = new Parse.File(logoFilename, {base64: httpImageFile.buffer.toString('base64')})

//Save logoFile
logoFile.save();

In v2.2.24 and above, I'm now getting unauthorized, even if I pass save({useMasterKey : true}). Again, as in #3051, VERBOSE shows nothing.

I pass all keys in constructor of ParseServer - as @steven-supersolid suggested in #3051.

Saving from the iOS client app however still works...

@Cliffordwh
Copy link

If its cloud based, you need to pass the Javascript key in your config!

How are you initializing the server? Pm2?

@MartinHerman
Copy link
Author

MartinHerman commented Dec 5, 2016

@Cliffordwh - As I've said, I'm passing all keys - masterKey, clientKey, restAPIKey, javascriptKey, dotNetKey when creating the constructor.

When I'm testing my Cloud Code Function that contains the Parse.File save(), I'm using curl with the REST endpoint /functions/my_function/ and passing the REST key as X-Parse-REST-API-Key in the header.

@Cliffordwh
Copy link

Cliffordwh commented Dec 5, 2016

There's your problem. Pass the X-Parse-Application-Id as well. That will resolve it!

@MartinHerman
Copy link
Author

@Cliffordwh - also passing that, and passing X-Parse-Session-Token if I want to simulate an authenticated user.

@Cliffordwh
Copy link

mmm thats strange. Sorry to ask, but you 100% sure there is no typo when creating the constructor and the keys correspond?

Could i ask you to curl without the X-Parse-Session-Token to see if you get a response?

@MartinHerman
Copy link
Author

MartinHerman commented Dec 5, 2016

@Cliffordwh - I'm 100% sure there is not typo. Not including X-Parse-Session-Token just returns the same unauthorized, as I'm not passing save({useMasterKey : true}) - which apparently is ignored anyway.

@Cliffordwh
Copy link

@MartinHerman the only last suggestion i can give is to remove client_key from the header.

I found this comment in a thread.

Then tried to include X-Parse-Client-Key in the request header (same value that is passed to server in index.js) and it does not work.
Then I removed the client key in the server initialisation (the code clientKey: process.env.CLIENT_KEY || '',) and it worked !!!

@MartinHerman
Copy link
Author

@Cliffordwh - I'm not passing a clientKey in the header. We can't remove it from the ParseServer constructor, as we're also using it for the mobile apps.

@Cliffordwh
Copy link

Sorry, i thought you said you where passing all keys. im trying to replicate this with little success.

@Cliffordwh
Copy link

Can you run with VERBOSE=1 to gather the server logs and paste them here?

@Cliffordwh
Copy link

Also check and make sure you passing serverURL

@hedegren
Copy link

hedegren commented Dec 5, 2016

You need to do this (add null):

logoFile.save(null, {useMasterKey:true});

@MartinHerman
Copy link
Author

@Cliffordwh - as I've already stated, VERBOSE shows nothing. The ServerURL is right as well, as all other calls work.

@hedegren - this is the standard format for Parse.Objects - however Parse.File.save() only wants one parameter, as per API reference.

@hedegren
Copy link

hedegren commented Dec 5, 2016

@MartinHerman True, however it seems that you must include the null as first parameter regardless what the docs says. Try it out and see for yourself.

@flovilmart
Copy link
Contributor

flovilmart commented Dec 5, 2016

@flovilmart
Copy link
Contributor

So for one, I believe we may have introduced an issue there, on the keys checking.

Where you do perform you file.save()? I presume in CloudCode.

Also, the file.save should work on any client, as you mentioned, this work fine on the iOS SDK.

Do you have set applicationId, javascriptKey, masterKey and serverURL in your parse-server configuration?

@hedegren
Copy link

hedegren commented Dec 5, 2016

@flovilmart
I might be wrong, but it seems when you pass the {useMasterKey:true} as the first argument, it will be the update fields. When I try it, i get:

Permission denied for action addField on class Jobs.

However, passing null as the first argument and the {useMasterKey:true} as the second, everything works as expected:

// THIS WORKS
var Job = Parse.Object.extend("Jobs");
var job = new Job();

job.set('title', 'test');
job.save(null, {
    useMasterKey: true
}).then(res => {
    console.log("Works"); 
}).catch(error => {
   console.log(error); 
});
// NOT WORKING
var Job = Parse.Object.extend("Jobs");
var job = new Job();

job.set('title', 'test');
job.save({
    useMasterKey: true
}).then(res => {
    console.log("Works"); 
}).catch(error => {
   console.log(error); 
});

@flovilmart
Copy link
Contributor

We're talking about saving a Parse.File not a Parse.Object

@danibjor
Copy link

danibjor commented Dec 5, 2016

Parse server 2.2.4 with Dashboard 1.0.19 will not save files from the Browser either.

Output form chrome console:

POST https://api.xx.com/parse/files/test.png 403 (Forbidden) dashboard.bundle.js:9703
XHR finished loading: POST "https://api.xx.com/parse/files/test.png".

Could those be related?

Edit: we use all keys in the server config

@flovilmart
Copy link
Contributor

@danibjor you mean 2.2.24? update to latest 2.2.25 please.

@MartinHerman
Copy link
Author

MartinHerman commented Dec 5, 2016

@flovilmart - yes, I'm performing it from CloudCode. I'm also setting everything in the constructor, and I'm 100% sure that the values match. See the constructor below. As for the client - I meant that I'm calling native client code from the Parse-iOS-SDK, not sending a request to CloudCode and handling the file there - and that works.

@danibjor - if its 2.2.24 or 2.2.25, it seems it could be related, as 403 indicates a permission error.

My ParseServer constructor:

var api = new ParseServer({
  databaseURI: process.env.MONGODB_URI,
  cloud: process.env.CLOUD_CODE_MAIN,
  appId: process.env.APP_ID,
  serverURL: process.env.SERVER_URL,
  masterKey: process.env.MASTER_KEY, 
  clientKey: process.env.CLIENT_KEY,
  restAPIKey: process.env.REST_API_KEY,
  javascriptKey: process.env.JAVASCRIPT_KEY,
  dotNetKey: process.env.DOT_NET_KEY,
  publicServerURL : process.env.SERVER_URL,
  filesAdapter: new S3Adapter(
    process.env.S3_ACCESS_KEY,
    process.env.S3_SECRET_KEY,
    process.env.S3_BUCKET,{
      directAccess: false,
      region: process.env.S3_BUCKET_REGION,
      bucketPrefix: process.env.S3_BUCKET_PREFIX
    }),
  push: {
    ios: [
      {
        pfx: './certificates/apns_dev.p12',
        passphrase: process.env.APNS_DEV_PASSWORD,
        bundleId: '***',
        production: false // Dev
      },
      {
        pfx: './certificates/apns_prod.p12',
        passphrase: process.env.APNS_PROD_PASSWORD,
        bundleId: '***',  
        production: true // Prod
      }
    ]
  }
});

@flovilmart
Copy link
Contributor

flovilmart commented Dec 5, 2016

what is the exact error you get when saving the file? I just ran some test locally (from the node SDK and latest version of parse-server) and I don't seem to be able to reproduce the issue.

I however managed to get unauthorized when my applicationId mismatched the server applicationID.

As you're on CloudCode, you should not need to call Parse.initialize. Is that called by anychance anywhere in your code with a bad applicationId?

@Cliffordwh
Copy link

@flovilmart i've spent 3 hours on this issue today with many different setups trying to replicate this issue and i cant. I do get unauthorized but only on the steps ive taken above.

@MartinHerman i understand you say there is nothing in the logs, but yet you haven't posted any logs for us to work with. Sometimes it the smallest things that are overlooked.

@flovilmart
Copy link
Contributor

@Cliffordwh what steps exactly? Also yes that's normal there's nothing in the log, I don't expect anything special in the logs as the request logger don't apply to the filesRouter (which is an issue in itself)

@Cliffordwh
Copy link

@flovilmart im with you!

@MartinHerman I might have a theory. Are you able to curl a std cloud function like this?

Parse.Cloud.define('hello', function(req, res) {
  res.success('Hi');
});

@MartinHerman
Copy link
Author

@flovilmart @Cliffordwh - guys, if you're ever in Slovakia, beers are on me.

So it turns out, I was missing the javascriptKey in my constructor after all. I am declaring it as an environment variable. With Heroku, you set them up in the application settings and if you're running your code locally, you load them from an .env file. For safety purposes, it is advised to add the .env file to gitignore.

When working on #3051, I've added my javascriptKey both to Heroku and my local .env file. The thing is - I've been using my home computer and I'm at the office now. As the production code pulls the environment variables from Heroku, no one noticed the new environment variables missing in their local .env files until we tried locally testing some new server code.

Again guys, if you are ever around, beers are on me!

@Cliffordwh
Copy link

@MartinHerman i thought so! lol glad you got it working. All the best

@flovilmart
Copy link
Contributor

Alight! Closing that! And enjoy the beers for us 🍻

@danibjor
Copy link

danibjor commented Dec 7, 2016

@flovilmart tried upgrading the server to 2.2.25 and updated dashboard to latest bits.

Console still show 403 on uploading files.

Failed to load resource: the server responded with a status of 403 (Forbidden)
https://api.xx.com/parse/files/phone.jpg

application/octet-stream
XHR
https://api.xx.xom/parse/files/phone.jpg
https
api.xx.com
/parse/files/phone.jpg
phone.jpg

Metode	POST
Buffered	No
Status	Forbidden
Kode	403

The class has CLP public read/write

@flovilmart
Copy link
Contributor

As @MartinHerman, make sure your keys are correctly set. If properly configured, it works correctly.

@FransGH
Copy link
Contributor

FransGH commented Dec 12, 2016

Had a similar issue. In your ParseServer constructor, try removing the javascriptKey.

@flovilmart
Copy link
Contributor

either remove the javascriptKey from parse-server constructor, or provide it in the dashboard.

@Hitabis
Copy link

Hitabis commented Dec 13, 2016

I also have this issue. I tried with and without the javascriptKey.
I allways get "unauthorized" while signing up a new user or even with the hello function from @Cliffordwh above.
I tried all versions above 2.2.24.

@MartinHerman
Copy link
Author

@Hitabis - could you post all fields of your Curl request and code from your ParseServer constructor?

@Hitabis
Copy link

Hitabis commented Dec 16, 2016

@MartinHerman the constructor is taken from the docker image https://github.com/yongjhih/docker-parse-server/blob/master/index.js

var api = new ParseServer({
    databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
    databaseOptions: databaseOptions,
    cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',

    appId: process.env.APP_ID || 'myAppId',
    masterKey: process.env.MASTER_KEY, //Add your master key here. Keep it secret!
    serverURL: serverURL,

    collectionPrefix: process.env.COLLECTION_PREFIX,
    clientKey: process.env.CLIENT_KEY,
    restAPIKey: process.env.REST_API_KEY,
    javascriptKey: process.env.JAVASCRIPT_KEY,
    dotNetKey: process.env.DOTNET_KEY,
    fileKey: process.env.FILE_KEY,
    filesAdapter: filesAdapter,

    facebookAppIds: facebookAppIds,
    maxUploadSize: process.env.MAX_UPLOAD_SIZE,
    push: pushConfig,
    verifyUserEmails: verifyUserEmails,
    emailAdapter: emailAdapter,
    enableAnonymousUsers: enableAnonymousUsers,
    allowClientClassCreation: allowClientClassCreation,
    //oauth = {},
    appName: process.env.APP_NAME,
    publicServerURL: process.env.PUBLIC_SERVER_URL,
    liveQuery: liveQueryParam
    //customPages: process.env.CUSTOM_PAGES || // {
    //invalidLink: undefined,
    //verifyEmailSuccess: undefined,
    //choosePassword: undefined,
    //passwordResetSuccess: undefined
    //}
});

I set APP_ID,APP_NAME,MASTER_KEY,JAVASCRIPT_KEY,REST_API_KEY and some others from outside.

I took the example function above:

Parse.Cloud.define('hello', function(req, res) {
  res.success('Hi');
});

and the curl request is:

curl -X POST \
-H "X-Parse-Application-Id: schneewittchen" \
-H "X-Parse-REST-API-Key: undefined" \
-H "X-Parse-Session-Token: r:b1c78b6c39759bf4da0097c3d23d94af" \
http://localhost:1337/parse/functions/hello

the resonse on 2.2.21 is

{
    "result": "Hi"
}

the resonse on 2.2.24 is

{
    "error": "unauthorized"
}

@FransGH
Copy link
Contributor

FransGH commented Dec 16, 2016

comment out "javascriptKey: process.env.JAVASCRIPT_KEY"

@Hitabis
Copy link

Hitabis commented Dec 16, 2016

@FransGH same situation. Can only access with master key.

@steven-supersolid
Copy link
Contributor

steven-supersolid commented Dec 16, 2016

You have specified at least one key in your server config. This means you must supply at least one key in any client call.

For your curl example you are passing a REST key with the string value undefined. If this does not match the REST key you provided when starting the server then authentication will fail. Session Tokens are not keys.

If you want to use request authentication then you must provide a valid key with every request.

If you don't want to use request authentication then remove all 4 client keys from your server config. This is not really any less secure and was the default before 2.24 if you didn't specify all keys.

@ngockhanhbl
Copy link

same issue :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants