URL: https://github.com/freeipa/freeipa/pull/535
Author: abbra
 Title: #535: add whoami command
Action: opened

PR body:
"""
`ipa whoami` command allows to query details about currently
authenticated identity. The command returns following information:

  * object class name
  * function to call to get actual details about the object
  * arguments to pass to the function
  * options to pass to the function

There are five types of objects that could bind to IPA using their
credentials. `ipa whoami` call expects one of the following:

  * users
  * staged users
  * hosts
  * Kerberos services
  * ID user override from the default trust view

The latter category of objects is automatically mapped by SASL GSSAPI
mapping rule in 389-ds for users from trusted Active Directory forests.

The command is expected to be used by Web UI to define proper view for
the authenticated identity.

Below is an example of how communication looks like for an Active
Directory user which has ID override in 'Default Trust View'.

    $ ipa -vv whoami
    ipa: INFO: trying https://ipa.example.com/ipa/session/json
    ipa: INFO: Forwarding 'whoami/1' to json server 
'https://ipa.example.com/ipa/session/json'
    ipa: INFO: Request: {
        "id": 0,
        "method": "whoami/1",
        "params": [
            [],
            {
                "version": "2.220"
            }
        ]
    }
    ipa: INFO: Response: {
        "error": null,
        "id": 0,
        "principal": "Administrator@AD.DOMAIN",
        "result": {
            "arguments": [
                "default trust view",
                "administrator@ad.domain"
            ],
            "details": "idoverrideuser_show/1",
            "object": "idoverrideuser",
            "options": []
        },
        "version": "<IPA VERSION>"
    }

Fixes https://pagure.io/freeipa/issue/6643
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/535/head:pr535
git checkout pr535
From f400b8021a7af27e9d377d3b28fff2ace4eadffc Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <aboko...@redhat.com>
Date: Thu, 2 Mar 2017 18:03:05 +0200
Subject: [PATCH] add whoami command

`ipa whoami` command allows to query details about currently
authenticated identity. The command returns following information:

  * object class name
  * function to call to get actual details about the object
  * arguments to pass to the function
  * options to pass to the function

There are five types of objects that could bind to IPA using their
credentials. `ipa whoami` call expects one of the following:

  * users
  * staged users
  * hosts
  * Kerberos services
  * ID user override from the default trust view

The latter category of objects is automatically mapped by SASL GSSAPI
mapping rule in 389-ds for users from trusted Active Directory forests.

The command is expected to be used by Web UI to define proper view for
the authenticated identity.

Below is an example of how communication looks like for an Active
Directory user which has ID override in 'Default Trust View'.

    $ ipa -vv whoami
    ipa: INFO: trying https://ipa.example.com/ipa/session/json
    ipa: INFO: Forwarding 'whoami/1' to json server 'https://ipa.example.com/ipa/session/json'
    ipa: INFO: Request: {
        "id": 0,
        "method": "whoami/1",
        "params": [
            [],
            {
                "version": "2.220"
            }
        ]
    }
    ipa: INFO: Response: {
        "error": null,
        "id": 0,
        "principal": "Administrator@AD.DOMAIN",
        "result": {
            "arguments": [
                "default trust view",
                "administrator@ad.domain"
            ],
            "details": "idoverrideuser_show/1",
            "object": "idoverrideuser",
            "options": []
        },
        "version": "<IPA VERSION>"
    }

Fixes https://pagure.io/freeipa/issue/6643
---
 API.txt                      |   8 +++
 VERSION.m4                   |   4 +-
 ipaclient/plugins/whoami.py  |  20 ++++++
 ipaserver/plugins/idviews.py |   5 ++
 ipaserver/plugins/whoami.py  | 141 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 176 insertions(+), 2 deletions(-)
 create mode 100644 ipaclient/plugins/whoami.py
 create mode 100644 ipaserver/plugins/whoami.py

diff --git a/API.txt b/API.txt
index a8f8ff1..16ee0ac 100644
--- a/API.txt
+++ b/API.txt
@@ -6441,6 +6441,13 @@ option: Str('version?')
 output: Entry('result')
 output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>])
 output: PrimaryKey('value')
+command: whoami/1
+args: 0,1,4
+option: Str('version?')
+output: Output('arguments', type=[<type 'list'>])
+output: Output('details', type=[<type 'unicode'>])
+output: Output('object', type=[<type 'unicode'>])
+output: Output('options', type=[<type 'list'>])
 default: aci/1
 default: aci_add/1
 default: aci_del/1
@@ -7005,6 +7012,7 @@ default: vaultcontainer_add_owner/1
 default: vaultcontainer_del/1
 default: vaultcontainer_remove_owner/1
 default: vaultcontainer_show/1
+default: whoami/1
 capability: messages 2.52
 capability: optional_uid_params 2.54
 capability: permissions2 2.69
diff --git a/VERSION.m4 b/VERSION.m4
index 8c93277..f943566 100644
--- a/VERSION.m4
+++ b/VERSION.m4
@@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000)
 #                                                      #
 ########################################################
 define(IPA_API_VERSION_MAJOR, 2)
-define(IPA_API_VERSION_MINOR, 219)
-# Last change: Support for Certificate Identity Mapping
+define(IPA_API_VERSION_MINOR, 220)
+# Last change: Add whoami command
 
 
 ########################################################
diff --git a/ipaclient/plugins/whoami.py b/ipaclient/plugins/whoami.py
new file mode 100644
index 0000000..68121e0
--- /dev/null
+++ b/ipaclient/plugins/whoami.py
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2017  FreeIPA Contributors see COPYING for license
+#
+
+import six
+
+from ipaclient.frontend import CommandOverride
+from ipalib.plugable import Registry
+
+if six.PY3:
+    unicode = str
+
+register = Registry()
+
+
+@register(override=True, no_fail=True)
+class whoami(CommandOverride):
+    def output_for_cli(self, textui, output, *args, **options):
+        for o in self.output:
+            textui.print_attribute(o, unicode(output[o]))
diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py
index 3ee2be4..b38a4ad 100644
--- a/ipaserver/plugins/idviews.py
+++ b/ipaserver/plugins/idviews.py
@@ -818,6 +818,11 @@ class idoverrideuser(baseidoverride):
     label_singular = _('User ID override')
     rdn_is_primary_key = True
 
+    # ID user overrides are bindable because we map SASL GSSAPI
+    # authentication of trusted users to ID user overrides in the
+    # default trust view.
+    bindable = True
+
     permission_filter_objectclasses = ['ipaUserOverride']
     managed_permissions = {
         'System: Read User ID Overrides': {
diff --git a/ipaserver/plugins/whoami.py b/ipaserver/plugins/whoami.py
new file mode 100644
index 0000000..48e36b7
--- /dev/null
+++ b/ipaserver/plugins/whoami.py
@@ -0,0 +1,141 @@
+#
+# Copyright (C) 2017  FreeIPA Contributors see COPYING for license
+#
+
+import six
+from ipalib import api, Command, errors, output, Str
+from ipalib import _
+from ipapython.dn import DN
+from ipalib.plugable import Registry
+from .idviews import DEFAULT_TRUST_VIEW_NAME
+
+if six.PY3:
+    unicode = str
+
+__doc__ = _("""
+Return a description of currently authenticated identity
+
+Who am I command returns information on who to get
+more details about the identity authenticated for this
+request. The information includes:
+
+ * type of object
+ * command to retrieve details of the object
+ * arguments and options to pass to the command
+
+EXAMPLES:
+
+ Look up as IPA user:
+   kinit admin
+   ipa whoami
+   ------------------------------------------
+   object: user
+   details: user_show/1
+   arguments: admin
+   options:
+   ------------------------------------------
+
+ Look up as a user from a trusted domain:
+   kinit user@AD.DOMAIN
+   ipa whoami
+   ------------------------------------------
+   object: idoverrideuser
+   details: idoverrideuser_show/1
+   arguments: ('default trust view', 'user@ad.domain')
+   options:
+   ------------------------------------------
+
+ Look up as a host:
+   kinit -k
+   ipa whoami
+   ------------------------------------------
+   object: host
+   details: host_show/1
+   arguments: ipa.example.com
+   options:
+   ------------------------------------------
+
+ Look up as a Kerberos service:
+   kinit -k -t /path/to/keytab HTTP/ipa.example.com
+   ipa whoami
+   ------------------------------------------
+   object: service
+   details: service_show/1
+   arguments: HTTP/ipa.example.com
+   options:
+   ------------------------------------------
+""")
+
+register = Registry()
+
+
+@register()
+class whoami(Command):
+    __doc__ = _('Describe currently authenticated identity.')
+
+    output_params = (
+        Str('object', label=_('Object class name')),
+        Str('details', label= _('Function to get details')),
+        Str('arguments*', label=_('Arguments to details function')),
+        Str('options*', label=_('Options to details function')),
+    )
+
+    has_output = (
+        output.Output('object', unicode, _('Object class name')),
+        output.Output('details', unicode, _('Function to get details')),
+        output.Output('arguments', list, _('Arguments to details function')),
+        output.Output('options', list, _('Options to details function')),
+    )
+
+    def execute(self, **options):
+        """
+        Retrieve the DN we are authenticated as to LDAP and find bindable IPA
+        object that handles the container where this DN belongs to. Then report
+        details about this object.
+        """
+        exceptions = dict(
+            idoverrideuser=(DN("cn={0}".format(DEFAULT_TRUST_VIEW_NAME)),
+                            DEFAULT_TRUST_VIEW_NAME, 'ipaOriginalUid'),
+        )
+        ldap = api.Backend.ldap2
+
+        # whoami_s() call returns a string 'dn: <actual DN value>'
+        # We also reject ldapi-as-root connections as DM is a virtual object
+        dn = DN(ldap.conn.whoami_s()[4:])
+        if dn == DN('cn=Directory Manager'):
+            raise errors.NotFound(
+                    reason=_('Cannot query Directory Manager with API'))
+
+        entry = ldap.get_entry(dn)
+        o_name = None
+        o_func = None
+        o_args = []
+        o_opts = []
+        for o in api.Object():
+            if not getattr(o, 'bindable', None):
+                continue
+            container = getattr(o, 'container_dn', None)
+            if container is None:
+                continue
+            # Adjust container for exception two-level objects
+            if o.name in exceptions:
+                container = exceptions[o.name][0] + container
+            if dn.find(container + api.env.basedn) == 1:
+                # We found exact container this DN belongs to
+                o_name = unicode(o.name)
+                o_args = [unicode(entry.single_value.get(o.primary_key.name))]
+                o_opts = []
+                o_func = unicode(o.methods.show.full_name)
+                if o.name in exceptions:
+                    o_args = [unicode(exceptions[o.name][1]),
+                              unicode(entry.single_value.get(
+                                      exceptions[o.name][2]))]
+                break
+
+        result = dict()
+        result['object'] = o_name
+        result['details'] = o_func
+        result['arguments'] = o_args
+        result['options'] = o_opts
+
+        return result
-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to