[
  {
    "comment": "verify login with current password, succeeds",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "root",
        "password": "password1!"
      }
    },
    "response": {
      "sessionName": "rootSession",
      "session": "token"
    }
  },

  {
    "comment": "change root password. no policy defined, so this works",
    "request": {
      "uri": "me/changePassword",
      "entity": {
        "oldPassword": "password1!",
        "newPassword": "password2!"
      }
    }
  },

  {
    "comment": "logout",
    "request": { "uri": "auth/logout" }
  },

  {
    "comment": "try to login as root with old password, fails",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "root",
        "password": "password1!"
      }
    },
    "response": {
      "status": 404
    }
  },

  {
    "comment": "try to login with new password, succeeds",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "root",
        "password": "password2!"
      }
    },
    "response": {
      "sessionName": "rootSession",
      "session": "token"
    }
  },

  {
    "comment": "get root policy (creates it)",
    "request": { "uri": "users/root/policy" },
    "response": {
      "store": "rootPolicy"
    }
  },

  {
    "comment": "update root policy, add authenticator",
    "include": "add_authenticator",
    "params": {
      "userId": "root",
      "authenticatorVar": "rootAuthenticator"
    }
  },

  {
    "comment": "re-read root policy, verify authenticator is required for account operations",
    "request": { "uri": "users/root/policy" },
    "response": {
      "store": "rootPolicy",
      "check": [
        {"condition": "json.getAccountContacts().length == 1"},
        {"condition": "json.getAuthenticator() != null"},
        {"condition": "json.getAuthenticator().requiredForAccountOperations() === true"}
      ]
    }
  },

  {
    "comment": "change root password again. policy requires authenticator token, so this fails",
    "request": {
      "uri": "me/changePassword",
      "entity": {
        "oldPassword": "password2!",
        "newPassword": "password3!"
      }
    },
    "response": {
      "status": 422,
      "check": [{"condition": "json.has('err.totpToken.required')"}]
    }
  },

  {
    "comment": "change root password with auth token, succeeds",
    "request": {
      "uri": "me/changePassword",
      "entity": {
        "oldPassword": "password2!",
        "newPassword": "password3!",
        "totpToken": "{{authenticator_token rootAuthenticator.totpKey}}"
      }
    }
  },

  {
    "comment": "try to login again with new password and totp token, succeeds",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "root",
        "password": "password3!",
        "totpToken": "{{authenticator_token rootAuthenticator.totpKey}}"
      }
    },
    "response": {
      "sessionName": "rootSession",
      "session": "token"
    }
  },

  {
    "comment": "create a non-admin user",
    "include": "new_account",
    "params": {
      "email": "user-change_password@example.com",
      "verifyEmail": "true"
    }
  },

  {
    "comment": "try to login as non-admin, succeeds",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "user-change_password@example.com",
        "password": "foobar1!"
      }
    },
    "response": {
      "sessionName": "userSession",
      "session": "token"
    }
  },

  {
    "comment": "as non-admin, read self-profile, succeeds",
    "request": { "uri": "me" },
    "response": {
      "check": [ {"condition": "json.getName() === 'user-change_password@example.com'"} ]
    }
  },

  {
    "comment": "as root, change non-admin user password, do not need to send old password, invalidates all sessions",
    "request": {
      "uri": "users/user-change_password@example.com/changePassword",
      "session": "rootSession",
      "entity": {
        "newPassword": "newuserpass1!"
      }
    }
  },

  {
    "comment": "as non-admin user, try to get profile, fails because session has been invalided",
    "request": {
      "session": "userSession",
      "uri": "me"
    },
    "response": {
      "status": 401
    }
  },

  {
    "comment": "as non-admin user, try to login with old password, fails",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "user-change_password@example.com",
        "password": "foobar1!"
      }
    },
    "response": {
      "status": 404
    }
  },

  {
    "comment": "as non-admin user, try to login with new password, succeeds",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "user-change_password@example.com",
        "password": "newuserpass1!"
      }
    },
    "response": {
      "sessionName": "userSession",
      "session": "token"
    }
  },

  {
    "comment": "as non-admin, read self policy, succeeds",
    "request": { "uri": "users/user-change_password@example.com/policy" },
    "response": { "store": "userPolicy" }
  },

  {
    "comment": "as non-admin user, change password, requires email auth",
    "request": {
      "uri": "me/changePassword",
      "entity": {
        "oldPassword": "newuserpass1!",
        "newPassword": "newuserpass2!"
      }
    },
    "response": {
      "check": [
        {"condition": "json.getMultifactorAuth() != null"},
        {"condition": "json.getMultifactorAuth().length == 1"},
        {"condition": "json.getMultifactorAuth()[0].getType().name() == 'email'"}
      ]
    }
  },

  {
    "before": "sleep 1s",
    "comment": "as root, check email inbox for password change request message",
    "request": {
      "session": "rootSession",
      "uri": "debug/inbox/email/user-change_password@example.com?type=request&action=password&target=account"
    },
    "response": {
      "store": "emailInbox",
      "check": [
        {"condition": "'{{json.[0].ctx.message.messageType}}' == 'request'"},
        {"condition": "'{{json.[0].ctx.message.action}}' == 'password'"},
        {"condition": "'{{json.[0].ctx.message.target}}' == 'account'"}
      ]
    }
  },

  {
    "comment": "as non-admin user, approve change password request without sending password, receive error",
    "request": {
      "session": "userSession",
      "uri": "auth/approve/{{emailInbox.[0].ctx.confirmationToken}}",
      "method": "post"
    },
    "response": {
      "status": 422,
      "check": [{"condition": "json.has('err.password.required')"}]
    }
  },

  {
    "comment": "as non-admin user, approve change password request and send password, succeeds",
    "request": {
      "uri": "auth/approve/{{emailInbox.[0].ctx.confirmationToken}}",
      "method": "post",
      "entity": [
        { "name": "account", "value": "user-change_password@example.com" },
        { "name": "password", "value": "new_password3!" }
      ]
    }
  },

  {
    "comment": "as non-admin user, try to login with new password set and approved by self, succeeds",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "user-change_password@example.com",
        "password": "new_password3!"
      }
    },
    "response": {
      "sessionName": "userSession",
      "session": "token"
    }
  },

  {
    "comment": "as non-admin user, update profile, set email as not required for account operations",
    "request": {
      "uri": "users/user-change_password@example.com/policy/contacts",
      "entity": {
        "type": "email",
        "info": "user-change_password@example.com",
        "requiredForAccountOperations": false
      }
    },
    "response": {
      "store": "userPolicy"
    }
  },

  {
    "comment": "as non-admin user, change password, succeeds with no auth required",
    "request": {
      "uri": "me/changePassword",
      "entity": {
        "oldPassword": "new_password3!",
        "newPassword": "new_password4!"
      }
    },
    "response": {
      "check": [
        {"condition": "json.getMultifactorAuth() == null"}
      ]
    }
  },

  {
    "comment": "as non-admin user, login again with new password no longer requiring email approval, succeeds",
    "request": {
      "session": "new",
      "uri": "auth/login",
      "entity": {
        "name": "user-change_password@example.com",
        "password": "new_password4!"
      }
    },
    "response": {
      "sessionName": "userSession",
      "session": "token"
    }
  },

  {
    "comment": "update user policy, add authenticator",
    "include": "add_authenticator",
    "params": {
      "userId": "user-change_password@example.com",
      "authenticatorVar": "userAuthenticator"
    }
  },

  {
    "comment": "re-read user policy, verify authenticator is required for account operations",
    "request": { "uri": "users/user-change_password@example.com/policy" },
    "response": {
      "store": "userPolicy",
      "check": [
        {"condition": "json.getAccountContacts().length == 2"},
        {"condition": "json.getAuthenticator() != null"},
        {"condition": "json.getAuthenticator().requiredForAccountOperations() === true"}
      ]
    }
  },

  {
    "comment": "as non-admin user, change password, fails because authenticator token is required",
    "request": {
      "uri": "me/changePassword",
      "entity": {
        "oldPassword": "new_password4!",
        "newPassword": "new_password5!"
      }
    },
    "response": {
      "status": 422,
      "check": [{"condition": "json.has('err.totpToken.required')"}]
    }
  },

  {
    "comment": "as non-admin user, change password, and send authenticator token, succeeds",
    "request": {
      "uri": "me/changePassword",
      "entity": {
        "oldPassword": "new_password4!",
        "newPassword": "new_password5!",
        "totpToken": "{{authenticator_token userAuthenticator.totpKey}}"
      }
    }
  }
]