{"id":215,"date":"2018-01-16T00:37:20","date_gmt":"2018-01-15T16:37:20","guid":{"rendered":"https:\/\/www.techcoil.com\/blog\/?p=215"},"modified":"2018-07-11T12:57:08","modified_gmt":"2018-07-11T04:57:08","slug":"how-to-enable-authenticated-mongodb-access-for-flask-mongoengine-applications","status":"publish","type":"post","link":"https:\/\/www.techcoil.com\/blog\/how-to-enable-authenticated-mongodb-access-for-flask-mongoengine-applications\/","title":{"rendered":"How to enable authenticated MongoDB access for Flask-MongoEngine applications"},"content":{"rendered":"<p>After having a <a href=\"https:\/\/www.techcoil.com\/blog\/my-first-look-at-mongodb-why-i-will-want-to-use-mongodb-in-my-next-project\/\" rel=\"noopener\" target=\"_blank\">first look at MongoDB more than 5 years back<\/a>, I told myself that I will use <a href=\"https:\/\/www.mongodb.com\/\" rel=\"noopener\" target=\"_blank\">MongoDB<\/a> to realise the next functionality of <a href=\"https:\/\/www.techcoil.com\" rel=\"noopener\" target=\"_blank\">Techcoil<\/a>. <\/p>\n<p>With exposure to <a href=\"https:\/\/docs.python.org\/3\/\" rel=\"noopener\" target=\"_blank\">Python 3<\/a>, <a href=\"http:\/\/flask.pocoo.org\/\" rel=\"noopener\" target=\"_blank\">Flask<\/a> and <a href=\"http:\/\/mongoengine.org\/\" rel=\"noopener\" target=\"_blank\">MongoEngine<\/a> in 2017, I had acquired the skills to build a <a href=\"https:\/\/www.techcoil.com\/shop\" rel=\"noopener\" target=\"_blank\">microsite to recommend gift ideas<\/a>. This microsite uses MongoDB to store the gift recommendation data.  <\/p>\n<p>With Flask and MongoEngine, development of this microsite did not take too much leisure time. With MongoDB not enforcing authentication, there were not much hindrance in setting up the development environment for this microsite.<\/p>\n<p>However, this free-for-all mode of accessing MongoDB is not recommended for production environments. Without authentication, it is easier for ill-intentioned people to mess up the backend database. <\/p>\n<p>To ensure that I have a go-to post for implementing authenticated access to MongoDB backed projects in the future, I document the steps needed for <a href=\"https:\/\/github.com\/MongoEngine\/flask-mongoengine\" rel=\"noopener\" target=\"_blank\">Flask-MongoEngine<\/a> applications to access MongoDB instances with access control turned on.<\/p>\n<h2>Enabling authenticated access for MongoDB<\/h2>\n<p>To enable authenticated access for MongoDB, we will need to follow through a the following steps at the MongoDB server end:<\/p>\n<ul>\n<li>An admin user account that can create new user accounts in MongoDB.<\/li>\n<li>MongoDB instance running with access control.<\/li>\n<li>A user account for our Flask + mongoengine application to interact with a database instance.<\/li>\n<\/ul>\n<h3>Creating the admin user account that can create new user accounts in MongoDB<\/h3>\n<p>With the free-for-all mode of MongoDB turned on, we first create the admin user account that will allow us to create new user accounts in MongoDB. The credentials for each user account will be kept in a MongoDB database instance. We typically refer to such database instance as the authentication database.<\/p>\n<p>MongoDB recommends that we put such user credentials inside the \"admin\" database instance. Since it is an admin user account, we will give it the \"userAdminAnyDatabase\" role so that we can create other user accounts later.<\/p>\n<p>To begin creating the admin user account, we use the <a href=\"https:\/\/docs.mongodb.com\/getting-started\/shell\/client\/\" rel=\"noopener\" target=\"_blank\"><code>MongoDB shell<\/code><\/a> to <a href=\"https:\/\/docs.mongodb.com\/tutorials\/connect-to-mongodb-shell\/\" rel=\"noopener\" target=\"_blank\">connect to our MongoDB instance<\/a>. The following command will connect the MongoDB shell to a MongoDB server instance listening on port 27017 locally.<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nmongo --port 27017\r\n<\/pre>\n<p>Once we got connected, we run the following commands to create the admin user:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nuse admin\r\ndb.createUser(\r\n  {\r\n    user: &quot;myAdmin&quot;,\r\n    pwd: &quot;passwordForAdmin&quot;,\r\n    roles: &#x5B; { role: &quot;userAdminAnyDatabase&quot;, db: &quot;admin&quot; } ]\r\n  }\r\n)\r\n<\/pre>\n<p>In the above set of commands, we first switch to the \"admin\" database and use the <a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/method\/db.createUser\/\" rel=\"noopener\" target=\"_blank\"><code>db.createUser<\/code><\/a> function to create the user account. <\/p>\n<p>We then feed in a JSON that describes the username, password and the role that the admin user will take. <\/p>\n<h3>Running MongoDB with access control<\/h3>\n<p>With the admin user created, the next step will be to make MongoDB run with access control. <\/p>\n<p>To do so, we can either update our MongoDB start script to run <code>mongod<\/code> with the <code>--auth<\/code> flag:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nmongod --auth --port 27017\r\n<\/pre>\n<p>Or add the following configurations to the configuration file that our MongoDB instance reads from:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nsecurity:\r\n  authorization: &quot;enabled&quot;\r\n<\/pre>\n<p>If we had installed MongoDB on Ubuntu through the mongodb-org meta-package, we will find the configuration file at <strong><code>\/etc\/mongod.conf<\/code><\/strong>.<\/p>\n<h3>Using MongoDB shell to connect to a MongoDB instance running in authentication mode<\/h3>\n<p>Once our MongoDB instance runs with access control, we will then run the following command to use MongoDB shell to interact with it again:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nmongo --port 27017 -u &quot;myAdmin&quot; -p --authenticationDatabase &quot;admin&quot;\r\n<\/pre>\n<p>This time round, we supplied the username of our admin user to the MongoDB shell. We also specify that we can MongoDB to check the supplied user credentials with the ones located inside the \"admin\" database instance. This command will prompt for the password of the admin user. Supply the password that you had created earlier.<\/p>\n<h3>Creating a user account for our Flask-MongoEngine application to interact with a database instance<\/h3>\n<p>Once we get into the MongoDB interactive shell successfully, we can then proceed with the creation of a user account that can only interact with the application database instance.<\/p>\n<p>To do so, we run the following set of commands:<\/p>\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\r\nuse admin\r\ndb.createUser(\r\n  {\r\n    user: &quot;appUser&quot;,\r\n    pwd: &quot;passwordForAppUser&quot;,\r\n    roles: &#x5B; { role: &quot;readWrite&quot;, db: &quot;app_db&quot; } ]\r\n  }\r\n)\r\n<\/pre>\n<p>In the above commands, we first switched to the \"admin\" database instance. We then created a user \"appUser\" with the \"<a href=\"https:\/\/docs.mongodb.com\/manual\/reference\/built-in-roles\/#readWrite\" rel=\"noopener\" target=\"_blank\">readWrite<\/a>\" role on the \"app_db\" database instance.  <\/p>\n<h2>Supplying the user account credentials to Flask-MongoEngine for interacting with the MongoDB database instance with access control<\/h2>\n<p>Once the MongoDB server side configurations are done, we can then include the following configurations to our Flask-MongoEngine application:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nfrom flask import Flask\r\nfrom flask_mongoengine import MongoEngine\r\n\r\napp = Flask(__name__)\r\napp.config&#x5B;'MONGODB_SETTINGS'] = {\r\n    'db': 'app_db',\r\n    'host': 'localhost',\r\n    'port': 27017,\r\n    'username': 'appUser',\r\n    'password': 'passwordForAppUser',\r\n    'authentication_source': 'admin'\r\n}\r\n\r\ndb = MongoEngine(app)\r\n<\/pre>\n<p>In the above codes, we specify the settings that we want Flask-MongoEngine to use for connecting to our MongoDB database instance with the user account that we had created earlier. We specify:<\/p>\n<ul>\n<li>the database instance via the 'db' key.<\/li>\n<li>the address of our MongoDB server via the 'host' key.<\/li>\n<li>the port where our MongoDB server listens to via the 'port' key.<\/li>\n<li>the username of our user account via the 'username' key.<\/li>\n<li>the password of our user account via the 'password' key.<\/li>\n<li>the MonogDB instance where our user account resides in via the 'authentication_source' key.<\/li>\n<\/ul>\n\n      <ul id=\"social-sharing-buttons-list\">\n        <li class=\"facebook\">\n          <a href=\"https:\/\/www.facebook.com\/sharer\/sharer.php?u=https%3A%2F%2Fwp.me%2Fp245TQ-3t\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n            <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Facebook.png\" alt=\"Facebook icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"twitter\">\n          <a href=\"https:\/\/twitter.com\/intent\/tweet?text=&url=https%3A%2F%2Fwp.me%2Fp245TQ-3t&via=Techcoil_com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Twitter.png\" alt=\"Twitter icon\"> Tweet\n          <\/a>\n        <\/li>\n        <li class=\"linkedin\">\n          <a href=\"https:\/\/www.linkedin.com\/shareArticle?mini=1&title=&url=https%3A%2F%2Fwp.me%2Fp245TQ-3t&source=https:\/\/www.techcoil.com\" target=\"_blank\" role=\"button\" rel=\"nofollow\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/linkedin.png\" alt=\"Linkedin icon\"> Share\n          <\/a>\n        <\/li>\n        <li class=\"pinterest\">\n          <a href=\"https:\/\/pinterest.com\/pin\/create\/button\/?url=https%3A%2F%2Fwww.techcoil.com%2Fblog%2Fwp-json%2Fwp%2Fv2%2Fposts%2F215&description=\" class=\"pin-it-button\" target=\"_blank\" role=\"button\" rel=\"nofollow\" count-layout=\"horizontal\">\n          <img decoding=\"async\" src=\"\/ph\/img\/3rd-party\/social-icons\/Pinterest.png\" alt=\"Pinterest icon\"> Save\n          <\/a>\n        <\/li>\n      <\/ul>\n    ","protected":false},"excerpt":{"rendered":"<p>After having a <a href=\"https:\/\/www.techcoil.com\/blog\/my-first-look-at-mongodb-why-i-will-want-to-use-mongodb-in-my-next-project\/\" rel=\"noopener\" target=\"_blank\">first look at MongoDB more than 5 years back<\/a>, I told myself that I will use <a href=\"https:\/\/www.mongodb.com\/\" rel=\"noopener\" target=\"_blank\">MongoDB<\/a> to realise the next functionality of <a href=\"https:\/\/www.techcoil.com\" rel=\"noopener\" target=\"_blank\">Techcoil<\/a>. <\/p>\n<p>With exposure to <a href=\"https:\/\/docs.python.org\/3\/\" rel=\"noopener\" target=\"_blank\">Python 3<\/a>, <a href=\"http:\/\/flask.pocoo.org\/\" rel=\"noopener\" target=\"_blank\">Flask<\/a> and <a href=\"http:\/\/mongoengine.org\/\" rel=\"noopener\" target=\"_blank\">MongoEngine<\/a> in 2017, I had acquired the skills to build a <a href=\"https:\/\/www.techcoil.com\/shop\" rel=\"noopener\" target=\"_blank\">microsite to recommend gift ideas<\/a>. This microsite uses MongoDB to store the gift recommendation data.  <\/p>\n<p>With Flask and MongoEngine, development of this microsite did not take too much leisure time. With MongoDB not enforcing authentication, there were not much hindrance in setting up the development environment for this microsite.<\/p>\n<p>However, this free-for-all mode of accessing MongoDB is not recommended for production environments. Without authentication, it is easier for ill-intentioned people to mess up the backend database. <\/p>\n<p>To ensure that I have a go-to post for implementing authenticated access to MongoDB backed projects in the future, I document the steps needed for <a href=\"https:\/\/github.com\/MongoEngine\/flask-mongoengine\" rel=\"noopener\" target=\"_blank\">Flask-MongoEngine<\/a> applications to access MongoDB instances with access control turned on.<\/p>\n","protected":false},"author":1,"featured_media":925,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"footnotes":""},"categories":[375,4],"tags":[478,480,152,481,226,233,254,255,195],"jetpack_featured_media_url":"https:\/\/www.techcoil.com\/blog\/wp-content\/uploads\/mongodb-logo-rgb-j6w271g1xn.jpg","jetpack_shortlink":"https:\/\/wp.me\/p245TQ-3t","jetpack-related-posts":[],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/215"}],"collection":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/comments?post=215"}],"version-history":[{"count":0,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/posts\/215\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media\/925"}],"wp:attachment":[{"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/media?parent=215"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/categories?post=215"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.techcoil.com\/blog\/wp-json\/wp\/v2\/tags?post=215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}