Skip to content

Password validation crashing Parse Server #3921

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

Closed
ZacharyKhan opened this issue Jun 10, 2017 · 5 comments
Closed

Password validation crashing Parse Server #3921

ZacharyKhan opened this issue Jun 10, 2017 · 5 comments

Comments

@ZacharyKhan
Copy link

ZacharyKhan commented Jun 10, 2017

Issue Description

I have a Parse Server deployed to Heroku that is utilizing the password validation introduced to parse server. I've added the code, without changing it, and got it to work part way. When I enter an invalid password, say BadPassword, it does its job and returns an error with the correct message. When I enter a valid password that fits within the requirements of the default validator pattern, the server crashes? See the logs below for a better look.

Steps to reproduce

  1. Deploy Parse Server Example to Heroku
  2. Setup to use password validation using the default pattern provided in the master repository
  3. Attempt to register with invalid password, returns an error successfully
  4. Attempt to register with valid password, crashes app

Expected Results

Successfully return an error for invalid passwords and allow registration for valid passwords

Actual Outcome

Explained in the issue description and logs very clearly

Environment Setup

  • Server

    • parse-server version: 2.4.2
    • Operating System: Ubuntu 16.04
    • Hardware: Not Sure
    • Localhost or remote server: Heroku
  • Database

    • MongoDB version: 3.2.x
    • Storage engine: mLab default (WiredTiger?)
    • Hardware: mLab Sandbox
    • Localhost or remote server: mLab

Logs/Trace

Here I try to use a password that does not fit the requirements in the validator pattern. It successfully returns the correct error 👍

screen shot 2017-06-10 at 4 09 40 am

Then, when I try to register with a password that does fit the requirements, the application crashes with ReferenceError: validatePassword is not defined 👎

screen shot 2017-06-10 at 4 11 49 am

@cherukumilli
Copy link
Contributor

@ZacharyKhan
Can you pls post the parse server initialization code?

adding @bhaskaryasa to this issue

@ZacharyKhan
Copy link
Author

ZacharyKhan commented Jun 11, 2017

@cherukumilli
Here is my entire index.js file from my Parse Server application code. I am using throng for web concurrency:

// Example express application adding the parse-server module to expose Parse
// compatible API routes.

var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var path = require('path');
var S3Adapter = require('parse-server').S3Adapter;

const throng = require('throng');
var WORKERS = process.env.WEB_CONCURRENCY || 1;

var databaseUri = process.env.MONGODB_URI;

if (!databaseUri) {
  console.log('DATABASE_URI not specified, falling back to localhost.');
}

var api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
  cloud: __dirname + '/cloud/main.js',
  appId: process.env.APP_ID,
  masterKey: process.env.MASTER_KEY, //Add your master key here. Keep it secret!
  serverURL: process.env.SERVER_URL,  // Don't forget to change to https if needed
  liveQuery: {
    classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
  },
  filesAdapter: new S3Adapter(
    process.env.S3_ACCESS_KEY,
    process.env.S3_SECRET_KEY,
    process.env.S3_BUCKET,
    {directAccess: true}
  ),
  // Enable email verification
  verifyUserEmails: true,
  // if `verifyUserEmails` is `true` and
  //     if `emailVerifyTokenValidityDuration` is `undefined` then
  //        email verify token never expires
  //     else
  //        email verify token expires after `emailVerifyTokenValidityDuration`
  //
  // `emailVerifyTokenValidityDuration` defaults to `undefined`
  //
  // email verify token below expires in 2 hours (= 2 * 60 * 60 == 7200 seconds)
  emailVerifyTokenValidityDuration: 10 * 60 * 60, // in seconds (2 hours = 7200 seconds)

  // set preventLoginWithUnverifiedEmail to false to allow user to login without verifying their email
  // set preventLoginWithUnverifiedEmail to true to prevent user from login if their email is not verified
  preventLoginWithUnverifiedEmail: true, // defaults to false

  // The public URL of your app.
  // This will appear in the link that is used to verify email addresses and reset passwords.
  // Set the mount path as it is in serverURL
  publicServerURL: process.env.SERVER_URL,
  // Your apps name. This will appear in the subject and body of the emails that are sent.
  appName: process.env.APP_NAME,
  // The email adapter
  emailAdapter: {
    module: 'parse-server-simple-mailgun-adapter',
    options: {
      // The address that your emails come from
      fromAddress: process.env.MAILGUN_SMTP_LOGIN,
      // Your domain from mailgun.com
      domain: process.env.MAILGUN_DOMAIN,
      // Your API key from mailgun.com
      apiKey: process.env.MAILGUN_API_KEY,
    }
  },
  // account lockout policy setting (OPTIONAL) - defaults to undefined
  // if the account lockout policy is set and there are more than `threshold` number of failed login attempts then the `login` api call returns error code `Parse.Error.OBJECT_NOT_FOUND` with error message `Your account is locked due to multiple failed login attempts. Please try again after <duration> minute(s)`. After `duration` minutes of no login attempts, the application will allow the user to try login again.
  accountLockout: {
    duration: 10, // duration policy setting determines the number of minutes that a locked-out account remains locked out before automatically becoming unlocked. Set it to a value greater than 0 and less than 100000.
    threshold: 5, // threshold policy setting determines the number of failed sign-in attempts that will cause a user account to be locked. Set it to an integer value greater than 0 and less than 1000.
  }
  ,
  // optional settings to enforce password policies
  passwordPolicy: {
          // Two optional settings to enforce strong passwords. Either one or both can be specified.
    // If both are specified, both checks must pass to accept the password
    // 1. a RegExp object or a regex string representing the pattern to enforce
    validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, // enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1 digit
    // 2. a callback function to be invoked to validate the password
    validatorCallback: (password) => { return validatePassword(password) },
    doNotAllowUsername: true, // optional setting to disallow username in passwords
    //optional setting to set a validity duration for password reset links (in seconds)
    resetTokenValidityDuration: 12*60*60, // expire after 12 hours
  }
});

function start() {
  var app = express();

  // Serve the Parse API on the /parse URL prefix
  var mountPath = process.env.PARSE_MOUNT || '/parse';
  app.use(mountPath, api);

  var httpServer = require('http').createServer(app);
  var server = httpServer.listen(process.env.PORT, function() {
    console.log('ParseServer running on port %s', server.address().port);
  });

  // This will enable the Live Query real-time server
  ParseServer.createLiveQueryServer(httpServer);
}

throng({
  workers: WORKERS,       // Number of workers (cpu count)
  lifetime: 10000,  // ms to keep cluster alive (Infinity)
  start: start    // Function to call when starting the worker processes
});

@cherukumilli
Copy link
Contributor

cherukumilli commented Jun 12, 2017

@ZacharyKhan
Looks like the following line is causing the problem:

validatorCallback: (password) => { return validatePassword(password) },

Can you please remove it and see if you still see the problem?

I think validatorCallback is only needed if you implement your own password validation routine. As you are using the

validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/,

a validatorCallback is not needed.

i.e., either use validatorPatter or use validatorCallback but not both.

If you want to implement your own validator then pls add a new function in your index.js called validatePassword() and remove the validatorPattern.

adding @bhaskaryasa to review my comments and keep me honest here.

@bhaskaryasa
Copy link
Contributor

@ZacharyKhan
As @cherukumilli rightly mentioned, it would cause a problem if validatePassword function is not defined. You can remove the setting 'validatorCallback' if you are not doing any additional validation other than the pattern.

@ZacharyKhan
Copy link
Author

@cherukumilli @bhaskaryasa That has fixed the problem, thank you 👍

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

3 participants