You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ra...@apache.org on 2017/07/28 13:59:42 UTC

[incubator-openwhisk] branch master updated: Add a database flag to completely block a given subject. (#2530)

This is an automated email from the ASF dual-hosted git repository.

rabbah pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git


The following commit(s) were added to refs/heads/master by this push:
     new 470130b  Add a database flag to completely block a given subject. (#2530)
470130b is described below

commit 470130b7b5db50e2349dc56cb7e9abb0f9cdb0b1
Author: Markus Thömmes <ma...@me.com>
AuthorDate: Fri Jul 28 15:59:40 2017 +0200

    Add a database flag to completely block a given subject. (#2530)
    
    There was no preservative way of blocking a user from the system temporarily before. This adds the functionality to provide a flag in the user's subject entry to block its keys from further usage.
---
 ansible/files/auth_index.json                      |  2 +-
 .../scala/whisk/core/admin/WskAdminTests.scala     | 62 ++++++++++++++++++++++
 tools/admin/wskadmin                               | 60 ++++++++++++++++++---
 3 files changed, 115 insertions(+), 9 deletions(-)

diff --git a/ansible/files/auth_index.json b/ansible/files/auth_index.json
index c9950b1..b1c4711 100644
--- a/ansible/files/auth_index.json
+++ b/ansible/files/auth_index.json
@@ -2,7 +2,7 @@
   "_id":"_design/subjects",
   "views": {
     "identities": {
-      "map": "function (doc) {\n  if(doc.uuid && doc.key) {\n    var v = {namespace: doc.subject, uuid: doc.uuid, key: doc.key};\n    emit([doc.subject], v);\n    emit([doc.uuid, doc.key], v);\n  }\n  if(doc.namespaces) {\n    doc.namespaces.forEach(function(namespace) {\n      var v = {namespace: namespace.name, uuid: namespace.uuid, key: namespace.key};\n      emit([namespace.name], v);\n      emit([namespace.uuid, namespace.key], v);\n    });\n  }\n}"
+      "map": "function (doc) {\n  if(doc.uuid && doc.key && !doc.blocked) {\n    var v = {namespace: doc.subject, uuid: doc.uuid, key: doc.key};\n    emit([doc.subject], v);\n    emit([doc.uuid, doc.key], v);\n  }\n  if(doc.namespaces && !doc.blocked) {\n    doc.namespaces.forEach(function(namespace) {\n      var v = {namespace: namespace.name, uuid: namespace.uuid, key: namespace.key};\n      emit([namespace.name], v);\n      emit([namespace.uuid, namespace.key], v);\n    });\n  }\n}"
     }
   },
   "language":"javascript",
diff --git a/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala b/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala
index ec4cf59..0d31758 100644
--- a/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala
+++ b/tests/src/test/scala/whisk/core/admin/WskAdminTests.scala
@@ -30,6 +30,7 @@ import common.WskAdmin
 import common.WskProps
 import whisk.core.entity.AuthKey
 import whisk.core.entity.Subject
+import common.TestUtils
 
 @RunWith(classOf[JUnitRunner])
 class WskAdminTests
@@ -91,4 +92,65 @@ class WskAdminTests
         val ns = wsk.namespace.whois()
         wskadmin.cli(Seq("user", "get", ns)).stdout.trim should be(wskprops.authKey)
     }
+
+    it should "block and unblock a user respectively" in {
+        val wskadmin = new RunWskAdminCmd {}
+        val auth = AuthKey()
+        val subject1 = Subject().asString
+        val subject2 = Subject().asString
+        val commonNamespace = "testspace"
+        try {
+            wskadmin.cli(Seq("user", "create", subject1, "-ns", commonNamespace, "-u", auth.compact))
+            wskadmin.cli(Seq("user", "create", subject2, "-ns", commonNamespace))
+
+            whisk.utils.retry({
+                // reverse lookup by namespace
+                val out = wskadmin.cli(Seq("user", "list", "-p", "2", "-k", commonNamespace)).stdout.trim
+                out should include(auth.compact)
+                out.lines should have size 2
+            }, 10, Some(1.second))
+
+            // block the user
+            wskadmin.cli(Seq("user", "block", subject1))
+
+            // wait until the user can no longer be found
+            whisk.utils.retry({
+                wskadmin.cli(Seq("user", "list", "-p", "2", "-k", commonNamespace)).stdout.trim.lines should have size 1
+            }, 10, Some(1.second))
+
+            // unblock the user
+            wskadmin.cli(Seq("user", "unblock", subject1))
+
+            // wait until the user can be found again
+            whisk.utils.retry({
+                val out = wskadmin.cli(Seq("user", "list", "-p", "2", "-k", commonNamespace)).stdout.trim
+                out should include(auth.compact)
+                out.lines should have size 2
+            }, 10, Some(1.second))
+        } finally {
+            wskadmin.cli(Seq("user", "delete", subject1)).stdout should include("Subject deleted")
+            wskadmin.cli(Seq("user", "delete", subject2)).stdout should include("Subject deleted")
+        }
+    }
+
+    it should "not allow edits on a blocked subject" in {
+        val wskadmin = new RunWskAdminCmd {}
+        val subject = Subject().asString
+        try {
+            // initially create the subject
+            wskadmin.cli(Seq("user", "create", subject))
+            // editing works
+            wskadmin.cli(Seq("user", "create", subject, "-ns", "testspace1"))
+            // block it
+            wskadmin.cli(Seq("user", "block", subject))
+            // Try to add a namespace, doesn't work
+            wskadmin.cli(Seq("user", "create", subject, "-ns", "testspace2"), expectedExitCode = TestUtils.ERROR_EXIT)
+            // Unblock the user
+            wskadmin.cli(Seq("user", "unblock", subject))
+            // Adding a namespace works
+            wskadmin.cli(Seq("user", "create", subject, "-ns", "testspace2"))
+        } finally {
+            wskadmin.cli(Seq("user", "delete", subject)).stdout should include("Subject deleted")
+        }
+    }
 }
diff --git a/tools/admin/wskadmin b/tools/admin/wskadmin
index 0e98c43..c149f04 100755
--- a/tools/admin/wskadmin
+++ b/tools/admin/wskadmin
@@ -105,6 +105,12 @@ def parseArgs():
     subcmd = subparser.add_parser('whois', help='identify user from an authorization key')
     subcmd.add_argument('authkey', help='the credentials to look up')
 
+    subcmd = subparser.add_parser('block', help='block a user')
+    subcmd.add_argument('subject', help='the user to block')
+
+    subcmd = subparser.add_parser('unblock', help='unblock a user')
+    subcmd.add_argument('subject', help='the user to unblock')
+
     subcmd = subparser.add_parser('list', help='list authorization keys associated with a namespace')
     subcmd.add_argument('namespace', help='the namespace to lookup')
     subcmd.add_argument('-p', '--pick', metavar='N', help='show no more than N identities', type=int, default=1)
@@ -141,6 +147,10 @@ def userCmd(args, props):
         return whoisUserCmd(args, props)
     elif args.subcmd == 'list':
         return listUserCmd(args, props)
+    elif args.subcmd == 'block':
+        return blockUserCmd(args, props)
+    elif args.subcmd == 'unblock':
+        return unblockUserCmd(args, props)
     else:
         print('unknown command')
         return 2
@@ -205,15 +215,19 @@ def createUserCmd(args, props):
             ]
         }
     else:
-        namespaces = filter(lambda ns: ns['name'] == desiredNamespace, doc['namespaces'])
-        if len(namespaces) == 0:
-            doc['namespaces'].append({
-                'name': desiredNamespace,
-                'uuid': uid,
-                'key': key
-            })
+        if not doc.get('blocked'):
+            namespaces = filter(lambda ns: ns['name'] == desiredNamespace, doc['namespaces'])
+            if len(namespaces) == 0:
+                doc['namespaces'].append({
+                    'name': desiredNamespace,
+                    'uuid': uid,
+                    'key': key
+                })
+            else:
+                print('Namespace already exists')
+                return 1
         else:
-            print('Namespace already exists')
+            print('The subject you want to edit is blocked')
             return 1
 
     res = insertIntoDatabase(props, doc, args.verbose)
@@ -415,6 +429,36 @@ def whoisUserCmd(args, props):
     print('Failed to get subject (%s)' % res.read().strip())
     return 1
 
+def blockUserCmd(args, props):
+    (doc, res) = getSubjectFromDb(args, props)
+
+    if doc is not None:
+        doc['blocked'] = True
+        insertRes = insertIntoDatabase(props, doc, args.verbose)
+        if insertRes.status in [201, 202]:
+            print('"%s" blocked successfully' % args.subject)
+        else:
+            print('Failed to block subject (%s)' % res.read().strip())
+            return 1
+    else:
+        print('Failed to get subject (%s)' % res.read().strip())
+        return 1
+
+def unblockUserCmd(args, props):
+    (doc, res) = getSubjectFromDb(args, props)
+
+    if doc is not None:
+        doc['blocked'] = False
+        insertRes = insertIntoDatabase(props, doc, args.verbose)
+        if insertRes.status in [201, 202]:
+            print('"%s" unblocked successfully' % args.subject)
+        else:
+            print('Failed to unblock subject (%s)' % res.read().strip())
+            return 1
+    else:
+        print('Failed to get subject (%s)' % res.read().strip())
+        return 1
+
 def getDbCmd(args, props):
     protocol = props[DB_PROTOCOL]
     host     = props[DB_HOST]

-- 
To stop receiving notification emails like this one, please contact
['"commits@openwhisk.apache.org" <co...@openwhisk.apache.org>'].