Esempio n. 1
0
def ldap_context(settings, use_cache=True):
    """Establishes an LDAP session context.

    Establishes a connection to the LDAP server from the `uri` in the
    ``settings`` and makes the context available in ``current_ldap``.

    Yields a namedtuple containing the connection to the server and the
    provider settings.

    :param settings: dict -- The settings for a LDAP provider.
    :param use_cache: bool -- If the connection should be cached.
    """
    try:
        connection = ldap_connect(settings, use_cache=use_cache)
        ldap_ctx = LDAPContext(connection=connection, settings=settings)
        _ldap_ctx_stack.push(ldap_ctx)
        try:
            yield ldap_ctx
        except ldap.LDAPError:
            # If something went wrong we get rid of cached connections.
            # This is mostly for the python shell where you have a very
            # long-living application context that usually results in
            # the ldap connection timing out.
            _clear_ldap_cache()
            raise
        finally:
            assert _ldap_ctx_stack.pop(
            ) is ldap_ctx, "Popped wrong LDAP context"
    except ldap.SERVER_DOWN:
        if has_app_context() and current_app.debug:
            raise
        raise MultipassException("The LDAP server is unreachable")
    except ldap.INVALID_CREDENTIALS:
        if has_app_context() and current_app.debug:
            raise
        raise ValueError("Invalid bind credentials")
    except ldap.SIZELIMIT_EXCEEDED:
        raise MultipassException(
            "Size limit exceeded (try setting a smaller page size)")
    except ldap.TIMELIMIT_EXCEEDED:
        raise MultipassException(
            "The time limit for the operation has been exceeded.")
    except ldap.TIMEOUT:
        raise MultipassException("The operation timed out.")
    except ldap.FILTER_ERROR:
        raise ValueError(
            "The filter supplied to the operation is invalid. "
            "(This is most likely due to a bad user or group filter.")
Esempio n. 2
0
 def __init__(self, *args, **kwargs):
     super(ShibbolethAuthProvider, self).__init__(*args, **kwargs)
     self.settings.setdefault('attrs_prefix', 'ADFS_')
     if not self.settings.get('callback_uri'):
         raise MultipassException("`callback_uri` must be specified in the provider settings")
     self.shibboleth_endpoint = '_flaskmultipass_shibboleth_' + self.name
     current_app.add_url_rule(self.settings['callback_uri'], self.shibboleth_endpoint,
                              self._shibboleth_callback, methods=('GET', 'POST'))
Esempio n. 3
0
    def search_identities_ex(self, criteria, exact=False, limit=None):
        if any(len(x) != 1 for x in criteria.values()):
            # Unfortunately the API does not support OR filters (yet?).
            # Fortunately we never search for more than one value anyway, except for emails when
            # looking up identities based on the user's email address.
            if len(criteria) != 1:
                raise MultipassException(
                    'This provider does not support multiple values for a search criterion',
                    provider=self)

            field, values = dict(criteria).popitem()
            seen = set()
            total = 0
            all_identities = []
            for value in values:
                identities = self.search_identities_ex({field: [value]},
                                                       exact=exact,
                                                       limit=limit)[0]
                for identity in identities:
                    if identity.identifier not in seen:
                        seen.add(identity.identifier)
                        all_identities.append(identity)
                        total += 1
            return all_identities, total

        criteria = {k: next(iter(v)) for k, v in criteria.items()}
        op = 'eq' if exact else 'contains'
        api_criteria = [
            '{}:{}:{}'.format(k, op, v) for k, v in criteria.items()
        ]
        api_criteria.append('type:eq:Person')
        api_criteria += self.settings['extra_search_filters']
        params = {
            'limit':
            limit or 5000,
            'filter':
            api_criteria,
            'field': [
                'upn',
                'firstName',
                'lastName',
                'displayName',
                'instituteName',
                'primaryAccountEmail',
            ],
        }

        with self._get_api_session() as api_session:
            results, total = self._fetch_all(api_session,
                                             '/api/v1.0/Identity',
                                             params,
                                             limit=limit)

        identities = []
        for res in results:
            del res['id']
            identities.append(IdentityInfo(self, res['upn'], **res))
        return identities, total
Esempio n. 4
0
 def __init__(self, *args, **kwargs):
     super(CASAuthProvider, self).__init__(*args, **kwargs)
     self.settings.setdefault('callback_uri',
                              '/cas_auth/{}'.format(self.name))
     if not self.settings.get('cas_url_base'):
         raise MultipassException(
             "`cas_url_base` must be specified in the provider settings")
     self.cas_client = CASClient(self.settings['cas_url_base'],
                                 auth_prefix='')
     self.cas_endpoint = '_flaskmultipass_cas_' + self.name
     current_app.add_url_rule(self.settings['callback_uri'],
                              self.cas_endpoint,
                              self._authorize_callback,
                              methods=('GET', 'POST'))
Esempio n. 5
0
 def __init__(self, *args, **kwargs):
     super(ShibbolethAuthProvider, self).__init__(*args, **kwargs)
     # convert everything to lowercase (headers/WSGI vars are case-insensitive)
     self.attrs_prefix = self.settings.setdefault('attrs_prefix',
                                                  'ADFS_').lower()
     self.attrs = [attr.lower() for attr in self.settings.get('attrs')]
     if not self.settings.get('callback_uri'):
         raise MultipassException(
             "`callback_uri` must be specified in the provider settings",
             provider=self)
     self.from_headers = self.settings.get('from_headers', False)
     self.shibboleth_endpoint = '_flaskmultipass_shibboleth_' + self.name
     current_app.add_url_rule(self.settings['callback_uri'],
                              self.shibboleth_endpoint,
                              self._shibboleth_callback,
                              methods=('GET', 'POST'))