示例#1
0
    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(ldap_mapping)
        self.name = 'ldap'
        self.description = """
Info plugin that uses LDAP to retrieve user data. """
        self.new_config(
            self.name,
            pconfig.String('server url', 'The LDAP server url.',
                           'ldap://example.com'),
            pconfig.Template('user dn template',
                             'Template to turn username into DN.',
                             'uid=%(username)s,ou=People,dc=example,dc=com'),
            pconfig.Pick('tls', 'What TLS level show be required',
                         ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
                         'Demand'),
            pconfig.String('bind dn',
                           'DN to bind as, if empty uses anonymous bind.',
                           'uid=ipsilon,ou=People,dc=example,dc=com'),
            pconfig.String('bind password',
                           'Password to use for bind operation'),
            pconfig.String('base dn',
                           'The base dn to look for users and groups',
                           'dc=example,dc=com'),
        )
示例#2
0
    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(posix_map)
        self.name = 'nss'
        self.description = """
Info plugin that uses the system NSS functions to retrieve user data."""
        self.new_config(self.name)
示例#3
0
 def _source_attributes(self, session):
     policy = Policy(self.cfg.default_attribute_mapping,
                     self.cfg.default_allowed_attributes)
     userattrs = session.get_user_attrs()
     mappedattrs, _ = policy.map_attributes(userattrs)
     attributes = policy.filter_attributes(mappedattrs)
     self.debug('Filterd attributes: %s' % repr(attributes))
     return attributes
示例#4
0
 def _source_attributes(self, session):
     policy = Policy(self.cfg.default_attribute_mapping,
                     self.cfg.default_allowed_attributes)
     userattrs = session.get_user_attrs()
     if 'email' not in userattrs and self.cfg.default_email_domain:
         userattrs['email'] = '%s@%s' % (userattrs['username'],
                                         self.cfg.default_email_domain)
     mappedattrs, _ = policy.map_attributes(userattrs)
     attributes = policy.filter_attributes(mappedattrs)
     self.debug('Filterd attributes: %s' % repr(attributes))
     return attributes
示例#5
0
 def _source_attributes(self, session):
     policy = Policy(self.cfg.default_attribute_mapping,
                     self.cfg.default_allowed_attributes)
     userattrs = session.get_user_attrs()
     if 'email' not in userattrs and self.cfg.default_email_domain:
         userattrs['email'] = '%s@%s' % (userattrs['_username'],
                                         self.cfg.default_email_domain)
     mappedattrs, _ = policy.map_attributes(userattrs)
     attributes = policy.filter_attributes(mappedattrs)
     self.debug('Filterd attributes: %s' % repr(attributes))
     return attributes
示例#6
0
    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(sssd_mapping)
        self.name = 'sssd'
        self.description = """
Info plugin that uses DBus to retrieve user data from SSSd."""
        self.bus = None
        self.new_config(
            self.name,
            pconfig.Condition('preconfigured',
                              'SSSD can only be used when pre-configured',
                              False),
        )
示例#7
0
    def __init__(self, *args):
        super(InfoProvider, self).__init__(*args)
        self.mapper = Policy(fasjson_mapping)

        self.name = 'fasjson'
        self.description = """
Info plugin that retrieves user data from FASJSON. """

        self.new_config(
            self.name,
            pconfig.String('FASJSON url', 'The FASJSON Url.',
                           'http://fasjson.tinystage.test/fasjson/'),
        )
示例#8
0
    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(ldap_mapping)
        self.name = 'ldap'
        self.description = """
Info plugin that uses LDAP to retrieve user data. """
        self.new_config(
            self.name,
            pconfig.String(
                'server url',
                'The LDAP server url.',
                'ldap://example.com'),
            pconfig.Template(
                'user dn template',
                'Template to turn username into DN.',
                'uid=%(username)s,ou=People,dc=example,dc=com'),
            pconfig.Pick(
                'tls',
                'What TLS level show be required',
                ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
                'Demand'),
            pconfig.String(
                'bind dn',
                'DN to bind as, if empty uses anonymous bind.',
                'uid=ipsilon,ou=People,dc=example,dc=com'),
            pconfig.String(
                'bind password',
                'Password to use for bind operation'),
            pconfig.String(
                'base dn',
                'The base dn to look for users and groups',
                'dc=example,dc=com'),
        )
示例#9
0
class InfoProvider(InfoProviderBase):
    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(posix_map)
        self.name = 'nss'
        self.description = """
Info plugin that uses the system NSS functions to retrieve user data."""
        self.new_config(self.name)

    def _get_posix_user(self, user):
        p = pwd.getpwnam(user)
        return {
            'username': p.pw_name,
            'uidNumber': p.pw_uid,
            'gidNumber': p.pw_gid,
            'gecos': p.pw_gecos,
            'homeDirectory': p.pw_dir,
            'loginShell': p.pw_shell
        }

    def _get_posix_groups(self, user, group):
        groups = set()
        getgrouplist = getattr(os, 'getgrouplist', None)
        if getgrouplist:
            ids = getgrouplist(user, group)
            for i in ids:
                try:
                    g = grp.getgrgid(i)
                    groups.add(g.gr_name)
                except KeyError:
                    pass

        else:
            g = grp.getgrgid(group)
            groups.add(g.gr_name)

            allg = grp.getgrall()
            for g in allg:
                if user in g.gr_mem:
                    groups.add(g.gr_name)

        return list(groups)

    def get_user_attrs(self, user):
        reply = dict()
        try:
            posix_user = self._get_posix_user(user)
            userattrs, extras = self.mapper.map_attributes(posix_user)
            groups = self._get_posix_groups(posix_user['username'],
                                            posix_user['gidNumber'])
            reply = userattrs
            reply['_groups'] = groups
            reply['_extras'] = {'posix': extras}

        except KeyError:
            pass

        return reply
示例#10
0
class InfoProvider(InfoProviderBase):

    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(sssd_mapping)
        self.name = 'sssd'
        self.new_config(
            self.name,
            pconfig.Condition(
                'preconfigured',
                'SSSD can only be used when pre-configured',
                False),
        )

    def _get_user_data(self, user):
        reply = dict()
        groups = []
        expectgroups = int(cherrypy.request.wsgi_environ.get(
            'REMOTE_USER_GROUP_N', 0))
        for key in cherrypy.request.wsgi_environ:
            if key.startswith('REMOTE_USER_'):
                if key == 'REMOTE_USER_GROUP_N':
                    continue
                if key.startswith('REMOTE_USER_GROUP_'):
                    groups.append(cherrypy.request.wsgi_environ[key])
                else:
                    reply[key] = cherrypy.request.wsgi_environ[key]
        if len(groups) != expectgroups:
            self.error('Number of groups expected was not found. Expected'
                       ' %d got %d' % (expectgroups, len(groups)))
        return reply, groups

    def get_user_attrs(self, user):
        reply = dict()
        try:
            attrs, groups = self._get_user_data(user)
            userattrs, extras = self.mapper.map_attributes(attrs)
            reply = userattrs
            reply['_groups'] = groups
            reply['_extras'] = {'sssd': extras}

        except KeyError:
            pass

        return reply

    def save_plugin_config(self, *args, **kwargs):
        raise ValueError('Configuration cannot be modified live for SSSD')

    def get_config_obj(self):
        return None

    def enable(self):
        self.refresh_plugin_config()
        if not self.get_config_value('preconfigured'):
            raise Exception("SSSD Can be enabled only if pre-configured")
        super(InfoProvider, self).enable()
示例#11
0
 def __init__(self, *pargs):
     super(InfoProvider, self).__init__(*pargs)
     self.mapper = Policy(sssd_mapping)
     self.name = 'sssd'
     self.new_config(
         self.name,
         pconfig.Condition(
             'preconfigured',
             'SSSD can only be used when pre-configured',
             False),
     )
示例#12
0
class InfoProvider(InfoProviderBase):

    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(posix_map)
        self.name = 'nss'
        self.new_config(self.name)

    def _get_posix_user(self, user):
        p = pwd.getpwnam(user)
        return {'username': p.pw_name, 'uidNumber': p.pw_uid,
                'gidNumber': p.pw_gid, 'gecos': p.pw_gecos,
                'homeDirectory': p.pw_dir, 'loginShell': p.pw_shell}

    def _get_posix_groups(self, user, group):
        groups = set()
        getgrouplist = getattr(os, 'getgrouplist', None)
        if getgrouplist:
            ids = getgrouplist(user, group)
            for i in ids:
                try:
                    g = grp.getgrgid(i)
                    groups.add(g.gr_name)
                except KeyError:
                    pass

        else:
            g = grp.getgrgid(group)
            groups.add(g.gr_name)

            allg = grp.getgrall()
            for g in allg:
                if user in g.gr_mem:
                    groups.add(g.gr_name)

        return list(groups)

    def get_user_attrs(self, user):
        reply = dict()
        try:
            posix_user = self._get_posix_user(user)
            userattrs, extras = self.mapper.map_attributes(posix_user)
            groups = self._get_posix_groups(posix_user['username'],
                                            posix_user['gidNumber'])
            reply = userattrs
            reply['_groups'] = groups
            reply['_extras'] = {'posix': extras}

        except KeyError:
            pass

        return reply
示例#13
0
class InfoProvider(InfoProviderBase):
    def __init__(self, *args):
        super(InfoProvider, self).__init__(*args)
        self.mapper = Policy(fasjson_mapping)

        self.name = 'fasjson'
        self.description = """
Info plugin that retrieves user data from FASJSON. """

        self.new_config(
            self.name,
            pconfig.String('FASJSON url', 'The FASJSON Url.',
                           'http://fasjson.tinystage.test/fasjson/'),
        )

    @property
    def fasjson_url(self):
        return self.get_config_value('FASJSON url')

    def get_user_attrs(self, user):
        try:
            client = fasjson_client.Client(url=self.fasjson_url)
            user_data = client.get_user(username=user).result
            user_group_data = client.list_user_groups(username=user).result
            user_agreements_data = client.list_user_agreements(
                username=user).result
        except Exception as e:
            self.error(f'FASJSON error: {e}')
            return

        # assumption that first email is the default
        user_data['email'] = user_data['emails'][0]

        # add the groups to the user_data
        user_data['groups'] = [g['groupname'] for g in user_group_data]

        # add the agreements to the user_data
        user_data['agreements'] = [g['name'] for g in user_agreements_data]

        userattrs, extras = self.mapper.map_attributes(user_data)
        self.debug(f'user_data: {user_data}')
        self.debug(f'Userattrs: {userattrs}')

        return userattrs
示例#14
0
class InfoProvider(InfoProviderBase):
    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(sssd_mapping)
        self.name = 'sssd'
        self.description = """
Info plugin that uses DBus to retrieve user data from SSSd."""
        self.bus = None
        self.new_config(
            self.name,
            pconfig.Condition('preconfigured',
                              'SSSD can only be used when pre-configured',
                              False),
        )

    def _get_user_data(self, user):
        reply = dict()
        groups = []

        # Get object for sssd infopipe
        infosssd_obj = self.bus.get_object('org.freedesktop.sssd.infopipe',
                                           '/org/freedesktop/sssd/infopipe')

        # Get Users object and interface from DBus
        users_obj = self.bus.get_object(
            'org.freedesktop.sssd.infopipe',
            '/org/freedesktop/sssd/infopipe/Users')
        users_if = dbus.Interface(users_obj,
                                  'org.freedesktop.sssd.infopipe.Users')

        # Get path, object, and interface for specific user
        user_path = users_if.FindByName(user)
        user_obj = self.bus.get_object('org.freedesktop.sssd.infopipe',
                                       user_path)

        # Get GECOS, attributes, and groups
        reply['gecos'] = user_obj.Get(
            'org.freedesktop.sssd.infopipe.Users.User',
            'gecos',
            dbus_interface=dbus.PROPERTIES_IFACE)
        user_attrs = user_obj.Get('org.freedesktop.sssd.infopipe.Users.User',
                                  'extraAttributes',
                                  dbus_interface=dbus.PROPERTIES_IFACE)
        user_groups = infosssd_obj.GetUserGroups(
            user, dbus_interface='org.freedesktop.sssd.infopipe')

        for group in user_groups:
            groups.append(group)

        for attr_name in user_attrs:
            attr_name = attr_name
            if len(user_attrs[attr_name]) == 1:
                reply[attr_name] = user_attrs[attr_name][0]
            else:
                reply[attr_name] = []
                for attr_val in user_attrs[attr_name]:
                    reply[attr_name].append(attr_val)

        return reply, groups

    def get_user_attrs(self, user):
        reply = dict()
        try:
            attrs, groups = self._get_user_data(user)
            userattrs, extras = self.mapper.map_attributes(attrs)
            reply = userattrs
            reply['_groups'] = groups
            reply['_extras'] = {'sssd': extras}

        except KeyError:
            pass

        return reply

    def save_plugin_config(self, *args, **kwargs):
        raise ValueError('Configuration cannot be modified live for SSSD')

    def get_config_obj(self):
        return None

    def enable(self):
        self.refresh_plugin_config()
        if not self.get_config_value('preconfigured'):
            raise Exception("SSSD Can be enabled only if pre-configured")
        self.bus = dbus.SystemBus()
        super(InfoProvider, self).enable()
示例#15
0
    }
except ImportError:
    CLA_GROUPS = dict()

fas_mapping = [
    ['username', 'nickname'],
    ['telephone', 'phone'],
    ['country_code', 'country'],
    ['human_name', 'fullname'],
    ['email', 'email'],
    ['timezone', 'timezone'],
    ['ssh_key', 'ssh_key'],
    ['gpg_keyid', 'gpg_keyid'],
]

fas_mapper = Policy(fas_mapping)

aws_idp_arn = 'arn:aws:iam::125523088429:saml-provider/id.fedoraproject.org'
aws_groups = {
    'aws-master': 'arn:aws:iam::125523088429:role/aws-master',
    'aws-iam': 'arn:aws:iam::125523088429:role/aws-iam',
    'aws-billing': 'arn:aws:iam::125523088429:role/aws-billing',
    'aws-atomic': 'arn:aws:iam::125523088429:role/aws-atomic',
    'aws-s3-readonly': 'arn:aws:iam::125523088429:role/aws-s3-readonly',
    'aws-fedoramirror': 'arn:aws:iam::125523088429:role/aws-fedoramirror',
    'aws-s3': 'arn:aws:iam::125523088429:role/aws-s3',
    'aws-cloud-poc': 'arn:aws:iam::125523088429:role/aws-cloud-poc',
    'aws-infra': 'arn:aws:iam::125523088429:role/aws-infra',
    'aws-docs': 'arn:aws:iam::125523088429:role/aws-docs',
    'aws-copr': 'arn:aws:iam::125523088429:role/aws-copr',
}
示例#16
0
class InfoProvider(InfoProviderBase):
    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(ldap_mapping)
        self.name = 'ldap'
        self.description = """
Info plugin that uses LDAP to retrieve user data. """
        self.new_config(
            self.name,
            pconfig.String('server url', 'The LDAP server url.',
                           'ldap://example.com'),
            pconfig.Template('user dn template',
                             'Template to turn username into DN.',
                             'uid=%(username)s,ou=People,dc=example,dc=com'),
            pconfig.Pick('tls', 'What TLS level show be required',
                         ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
                         'Demand'),
            pconfig.String('bind dn',
                           'DN to bind as, if empty uses anonymous bind.',
                           'uid=ipsilon,ou=People,dc=example,dc=com'),
            pconfig.String('bind password',
                           'Password to use for bind operation'),
            pconfig.String('base dn',
                           'The base dn to look for users and groups',
                           'dc=example,dc=com'),
        )

    @property
    def server_url(self):
        return self.get_config_value('server url')

    @property
    def tls(self):
        return self.get_config_value('tls')

    @property
    def bind_dn(self):
        return self.get_config_value('bind dn')

    @property
    def bind_password(self):
        return self.get_config_value('bind password')

    @property
    def user_dn_tmpl(self):
        return self.get_config_value('user dn template')

    @property
    def base_dn(self):
        return self.get_config_value('base dn')

    def _ldap_bind(self):

        tls = self.tls.lower()
        tls_req_opt = None
        if tls == "never":
            tls_req_opt = ldap.OPT_X_TLS_NEVER
        elif tls == "demand":
            tls_req_opt = ldap.OPT_X_TLS_DEMAND
        elif tls == "allow":
            tls_req_opt = ldap.OPT_X_TLS_ALLOW
        elif tls == "try":
            tls_req_opt = ldap.OPT_X_TLS_TRY
        if tls_req_opt is not None:
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt)

        conn = ldap.initialize(self.server_url)

        if tls != "notls":
            if not self.server_url.startswith("ldaps"):
                conn.start_tls_s()

        if ((self.bind_dn is None and self.bind_password is None)
                or (self.bind_dn == '' and self.bind_password == '')):
            conn.simple_bind_s()
        else:
            conn.simple_bind_s(self.bind_dn, self.bind_password)

        return conn

    def _get_user_data(self, conn, dn):
        result = conn.search_s(dn, ldap.SCOPE_BASE)
        if result is None or result == []:
            raise Exception('User object could not be found!')
        elif len(result) > 1:
            raise Exception('No unique user object could be found!')
        data = dict()
        for name, value in result[0][1].iteritems():
            if isinstance(value, list) and len(value) == 1:
                value = value[0]
            data[name] = value
        return data

    def _get_user_groups(self, conn, base, username):
        # TODO: fixme to support RFC2307bis schemas
        results = conn.search_s(base,
                                ldap.SCOPE_SUBTREE,
                                filterstr='memberuid=%s' % username)
        if results is None or results == []:
            self.debug('No groups for %s' % username)
            return []
        groups = []
        for r in results:
            if 'cn' in r[1]:
                groups.append(r[1]['cn'][0])
        return groups

    def get_user_data_from_conn(self, conn, dn, base, username):
        reply = dict()
        try:
            ldapattrs = self._get_user_data(conn, dn)
            self.debug('LDAP attrs for %s: %s' % (dn, ldapattrs))
            userattrs, extras = self.mapper.map_attributes(ldapattrs)
            groups = self._get_user_groups(conn, base, username)
            reply = userattrs
            reply['_groups'] = groups
            reply['_extras'] = {'ldap': extras}
        except Exception as e:  # pylint: disable=broad-except
            self.error('Error fetching/mapping LDAP user data: %s' % e)

        return reply

    def get_user_attrs(self, user):
        try:
            dn = self.user_dn_tmpl % {'username': user}
        except ValueError as e:
            self.error('DN generation failed with template %s, user %s: %s' %
                       (self.user_dn_tmpl, user, e))
            return {}
        except Exception as e:  # pylint: disable=broad-except
            self.error('Unhandled error generating DN from %s, user %s: %s' %
                       (self.user_dn_tmpl, user, e))
            return {}

        try:
            base = self.base_dn
            conn = self._ldap_bind()
            return self.get_user_data_from_conn(conn, dn, base, user)
        except ldap.LDAPError as e:
            self.error('LDAP search failed for DN %s on base %s: %s' %
                       (dn, base, e))
            return {}
        except Exception as e:  # pylint: disable=broad-except
            self.error('Unhandled LDAP error for DN %s on base %s: %s' %
                       (dn, base, e))
            return {}
示例#17
0
class InfoProvider(InfoProviderBase):

    def __init__(self, *pargs):
        super(InfoProvider, self).__init__(*pargs)
        self.mapper = Policy(ldap_mapping)
        self.name = 'ldap'
        self.description = """
Info plugin that uses LDAP to retrieve user data. """
        self.new_config(
            self.name,
            pconfig.String(
                'server url',
                'The LDAP server url.',
                'ldap://example.com'),
            pconfig.Template(
                'user dn template',
                'Template to turn username into DN.',
                'uid=%(username)s,ou=People,dc=example,dc=com'),
            pconfig.Pick(
                'tls',
                'What TLS level show be required',
                ['Demand', 'Allow', 'Try', 'Never', 'NoTLS'],
                'Demand'),
            pconfig.String(
                'bind dn',
                'DN to bind as, if empty uses anonymous bind.',
                'uid=ipsilon,ou=People,dc=example,dc=com'),
            pconfig.String(
                'bind password',
                'Password to use for bind operation'),
            pconfig.String(
                'base dn',
                'The base dn to look for users and groups',
                'dc=example,dc=com'),
        )

    @property
    def server_url(self):
        return self.get_config_value('server url')

    @property
    def tls(self):
        return self.get_config_value('tls')

    @property
    def bind_dn(self):
        return self.get_config_value('bind dn')

    @property
    def bind_password(self):
        return self.get_config_value('bind password')

    @property
    def user_dn_tmpl(self):
        return self.get_config_value('user dn template')

    @property
    def base_dn(self):
        return self.get_config_value('base dn')

    def _ldap_bind(self):

        tls = self.tls.lower()
        tls_req_opt = None
        if tls == "never":
            tls_req_opt = ldap.OPT_X_TLS_NEVER
        elif tls == "demand":
            tls_req_opt = ldap.OPT_X_TLS_DEMAND
        elif tls == "allow":
            tls_req_opt = ldap.OPT_X_TLS_ALLOW
        elif tls == "try":
            tls_req_opt = ldap.OPT_X_TLS_TRY
        if tls_req_opt is not None:
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, tls_req_opt)

        conn = ldap.initialize(self.server_url)

        if tls != "notls":
            if not self.server_url.startswith("ldaps"):
                conn.start_tls_s()

        if ((self.bind_dn is None and self.bind_password is None) or
                (self.bind_dn == '' and self.bind_password == '')):
            conn.simple_bind_s()
        else:
            conn.simple_bind_s(self.bind_dn, self.bind_password)

        return conn

    def _get_user_data(self, conn, dn):
        result = conn.search_s(dn, ldap.SCOPE_BASE)
        if result is None or result == []:
            raise Exception('User object could not be found!')
        elif len(result) > 1:
            raise Exception('No unique user object could be found!')
        data = dict()
        for name, value in result[0][1].iteritems():
            if isinstance(value, list) and len(value) == 1:
                value = value[0]
            data[name] = value
        return data

    def _get_user_groups(self, conn, base, username):
        # TODO: fixme to support RFC2307bis schemas
        results = conn.search_s(base, ldap.SCOPE_SUBTREE,
                                filterstr='memberuid=%s' % username)
        if results is None or results == []:
            self.debug('No groups for %s' % username)
            return []
        groups = []
        for r in results:
            if 'cn' in r[1]:
                groups.append(r[1]['cn'][0])
        return groups

    def get_user_data_from_conn(self, conn, dn, base, username):
        reply = dict()
        try:
            ldapattrs = self._get_user_data(conn, dn)
            self.debug('LDAP attrs for %s: %s' % (dn, ldapattrs))
            userattrs, extras = self.mapper.map_attributes(ldapattrs)
            groups = self._get_user_groups(conn, base, username)
            reply = userattrs
            reply['_groups'] = groups
            reply['_extras'] = {'ldap': extras}
        except Exception, e:  # pylint: disable=broad-except
            self.error('Error fetching/mapping LDAP user data: %s' % e)

        return reply
示例#18
0
    def saml2checks(self, login):

        us = UserSession()
        user = us.get_user()
        if user.is_anonymous:
            if self.stage == 'init':
                returl = '%s/saml2/SSO/Continue?%s' % (
                    self.basepath, self.trans.get_GET_arg())
                data = {
                    'saml2_stage': 'auth',
                    'saml2_request': login.dump(),
                    'login_return': returl,
                    'login_target': login.remoteProviderId
                }
                self.trans.store(data)
                redirect = '%s/login?%s' % (self.basepath,
                                            self.trans.get_GET_arg())
                raise cherrypy.HTTPRedirect(redirect)
            else:
                raise AuthenticationError("Unknown user",
                                          lasso.SAML2_STATUS_CODE_AUTHN_FAILED)

        self._audit("Logged in user: %s [%s]" % (user.name, user.fullname))

        # We can wipe the transaction now, as this is the last step
        self.trans.wipe()

        # TODO: check if this is the first time this user access this SP
        # If required by user prefs, ask user for consent once and then
        # record it
        consent = True

        # TODO: check destination

        try:
            provider = ServiceProvider(self.cfg, login.remoteProviderId)
            nameidfmt = provider.get_valid_nameid(login.request.nameIdPolicy)
        except NameIdNotAllowed as e:
            raise AuthenticationError(
                str(e), lasso.SAML2_STATUS_CODE_INVALID_NAME_ID_POLICY)
        except InvalidProviderId as e:
            raise AuthenticationError(str(e),
                                      lasso.SAML2_STATUS_CODE_AUTHN_FAILED)

        # TODO: check login.request.forceAuthn

        login.validateRequestMsg(not user.is_anonymous, consent)

        authtime = datetime.datetime.utcnow()
        skew = datetime.timedelta(0, 60)
        authtime_notbefore = authtime - skew
        authtime_notafter = authtime + skew

        # Let's first do the attribute mapping, so we could map the username
        # Check attribute policy and perform mapping and filtering.
        # If the SP has its own mapping or filtering policy use that
        # instead of the global policy.
        if (provider.attribute_mappings is not None
                and len(provider.attribute_mappings) > 0):
            attribute_mappings = provider.attribute_mappings
        else:
            attribute_mappings = self.cfg.default_attribute_mapping
        if (provider.allowed_attributes is not None
                and len(provider.allowed_attributes) > 0):
            allowed_attributes = provider.allowed_attributes
        else:
            allowed_attributes = self.cfg.default_allowed_attributes
        self.debug("Allowed attrs: %s" % allowed_attributes)
        self.debug("Mapping: %s" % attribute_mappings)
        policy = Policy(attribute_mappings, allowed_attributes)
        userattrs = us.get_user_attrs()
        mappedattrs, _ = policy.map_attributes(userattrs)
        attributes = policy.filter_attributes(mappedattrs)

        if '_groups' in attributes and 'groups' not in attributes:
            attributes['groups'] = attributes['_groups']

        self.debug("%s's attributes: %s" % (user.name, attributes))

        # Perform authorization check.
        # We use the raw userattrs here so that we can make decisions based
        # on attributes we don't want to send to the SP
        provinfo = {
            'name': provider.name,
            'url': provider.splink,
            'owner': provider.owner
        }
        if not self._site['authz'].authorize_user('saml2', provinfo, user.name,
                                                  userattrs):
            self.trans.wipe()
            self.error('Authorization denied by authorization provider')
            raise AuthenticationError("Authorization denied",
                                      lasso.SAML2_STATUS_CODE_AUTHN_FAILED)

        # TODO: get authentication type fnd name format from session
        # need to save which login manager authenticated and map it to a
        # saml2 authentication context
        authn_context = lasso.SAML2_AUTHN_CONTEXT_UNSPECIFIED

        timeformat = '%Y-%m-%dT%H:%M:%SZ'
        login.buildAssertion(authn_context, authtime.strftime(timeformat),
                             None, authtime_notbefore.strftime(timeformat),
                             authtime_notafter.strftime(timeformat))

        nameid = None
        if nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT:
            idpsalt = self.cfg.idp_nameid_salt
            if idpsalt is None:
                raise AuthenticationError(
                    "idp nameid salt is not set in configuration")
            value = hashlib.sha512()
            value.update(idpsalt)
            value.update(login.remoteProviderId)
            value.update(mappedattrs.get('_username'))
            nameid = '_' + value.hexdigest()
        elif nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT:
            nameid = '_' + uuid.uuid4().hex
        elif nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_KERBEROS:
            nameid = userattrs.get('gssapi_principal_name')
        elif nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_EMAIL:
            nameid = mappedattrs.get('email')
            if not nameid:
                nameid = '%s@%s' % (user.name, self.cfg.default_email_domain)
        elif nameidfmt == lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED:
            nameid = provider.normalize_username(mappedattrs.get('_username'))

        if nameid:
            login.assertion.subject.nameId.format = nameidfmt
            login.assertion.subject.nameId.content = nameid
        else:
            self.trans.wipe()
            self.error('Authentication succeeded but it was not ' +
                       'provided by NameID %s' % nameidfmt)
            raise AuthenticationError("Unavailable Name ID type",
                                      lasso.SAML2_STATUS_CODE_AUTHN_FAILED)

        # The saml-core-2.0-os specification section 2.7.3 requires
        # the AttributeStatement element to be non-empty.
        if attributes:
            if not login.assertion.attributeStatement:
                attrstat = lasso.Saml2AttributeStatement()
                login.assertion.attributeStatement = [attrstat]
            else:
                attrstat = login.assertion.attributeStatement[0]
            if not attrstat.attribute:
                attrstat.attribute = ()

        for key in attributes:
            # skip internal info
            if key[0] == '_':
                continue
            values = attributes[key]
            if isinstance(values, dict):
                continue
            if not isinstance(values, list):
                values = [values]
            attr = lasso.Saml2Attribute()
            attr.name = key
            attr.nameFormat = lasso.SAML2_ATTRIBUTE_NAME_FORMAT_BASIC
            attr.attributeValue = []
            vals = []
            for value in values:
                if value is None:
                    self.log('Ignoring None value for attribute %s' % key)
                    continue
                self.debug('value %s' % value)
                node = lasso.MiscTextNode.newWithString(value)
                node.textChild = True
                attrvalue = lasso.Saml2AttributeValue()
                attrvalue.any = [node]
                vals.append(attrvalue)

            attr.attributeValue = vals
            attrstat.attribute = attrstat.attribute + (attr, )

        self.debug('Assertion: %s' % login.assertion.dump())

        saml_sessions = self.cfg.idp.sessionfactory

        lasso_session = lasso.Session()
        lasso_session.addAssertion(login.remoteProviderId, login.assertion)
        provider = ServiceProvider(self.cfg, login.remoteProviderId)
        saml_sessions.add_session(login.assertion.id, login.remoteProviderId,
                                  user.name, lasso_session.dump(), None,
                                  provider.logout_mechs)
示例#19
0
 def __init__(self, *pargs):
     super(InfoProvider, self).__init__(*pargs)
     self.mapper = Policy(posix_map)
     self.name = 'nss'
     self.new_config(self.name)