diff --git a/API.txt b/API.txt index ace3101dc..90cda748a 100644 --- a/API.txt +++ b/API.txt @@ -6451,6 +6451,12 @@ option: Str('version?') output: Entry('result') output: Output('summary', type=[, ]) output: PrimaryKey('value') +command: whoami/1 +args: 0,1,3 +option: Str('version?') +output: Output('arguments', type=[]) +output: Output('command', type=[]) +output: Output('object', type=[]) default: aci/1 default: aci_add/1 default: aci_del/1 @@ -7017,6 +7023,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 8c9327731..f9435664d 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/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py index 3ee2be4a9..b38a4ad17 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 000000000..0ec6bb8a7 --- /dev/null +++ b/ipaserver/plugins/whoami.py @@ -0,0 +1,136 @@ +# +# 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 information about currently authenticated identity + +Who am I command returns information on how 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 + +The information is returned as a dictionary. Examples below use +'key: value' output for illustrative purposes. + +EXAMPLES: + + Look up as IPA user: + kinit admin + ipa console + >> api.Command.whoami() + ------------------------------------------ + object: user + command: user_show/1 + arguments: admin + ------------------------------------------ + + Look up as a user from a trusted domain: + kinit user@AD.DOMAIN + ipa console + >> api.Command.whoami() + ------------------------------------------ + object: idoverrideuser + command: idoverrideuser_show/1 + arguments: ('default trust view', 'user@ad.domain') + ------------------------------------------ + + Look up as a host: + kinit -k + ipa console + >> api.Command.whoami() + ------------------------------------------ + object: host + command: host_show/1 + arguments: ipa.example.com + ------------------------------------------ + + Look up as a Kerberos service: + kinit -k -t /path/to/keytab HTTP/ipa.example.com + ipa console + >> api.Command.whoami() + ------------------------------------------ + object: service + command: service_show/1 + arguments: HTTP/ipa.example.com + ------------------------------------------ +""") + +register = Registry() + + +@register() +class whoami(Command): + __doc__ = _('Describe currently authenticated identity.') + + NO_CLI = True + + output_params = ( + Str('object', label=_('Object class name')), + Str('command', label= _('Function to get details')), + Str('arguments*', label=_('Arguments to details function')), + ) + + has_output = ( + output.Output('object', unicode, _('Object class name')), + output.Output('command', unicode, _('Function to get details')), + output.Output('arguments', list, _('Arguments 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 = { + '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: ' + # 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 = [] + 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_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 + + return {'object': o_name, 'command': o_func, 'arguments': o_args}