示例#1
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using '),
        ('required', '{title} is required. You can assign it '
                     'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
                                'trying to access {service_name}. '
                                'Unfortunately, we are not accepting new '
                                'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
                         'Please use one of your other available methods '
                         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png'))
    )

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'required': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        self.module_policies['automoderate'] = not \
            astakos_settings.MODERATION_ENABLED
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def update_last_login_at(self):
        instance = self._instance
        user = instance.user.__class__.objects.get(pk=instance.user.pk)
        date = datetime.now()
        instance.last_login_at = user.last_login = date
        instance.save()
        user.save()

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        # db lock
        objects = self.user.__class__.objects
        self.user = objects.select_for_update().get(pk=self.user.pk)

        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy",
                     group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.base_project and user.base_project.delete()
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    tpl = smart_unicode(msg)
                    self.message_tpls_compiled[key] = tpl.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError, e:
                    continue
        else:
示例#2
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using '),
        ('required', '{title} is required. You can assign it '
         'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
         'trying to access {service_name}. '
         'Unfortunately, we are not accepting new '
         'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
         'Please use one of your other available methods '
         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png')))

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'required': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        self.module_policies['automoderate'] = not \
            astakos_settings.MODERATION_ENABLED
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy", group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    self.message_tpls_compiled[key] = msg.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError, e:
                    continue
        else:
示例#3
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using {account_prompt}'),
        ('required', '{title} is required. You can assign it '
         'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
         'trying to access {service_name}. '
         'Unfortunately, we are not accepting new '
         'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
         'Please use one of your other available methods '
         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png')))

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'mirror_groups': False,  # Currently used only by LDAP
        'required': False,
        'autoverify': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    # Mapping of provider's attributes to attributes of AstakosUser.
    # The second element of the tuple dictates whether the attribute can be
    # changed by the user or is automatically set by the provider in every
    # login.
    # Identifier is used to get the unique user identifier of the third
    # party provider!
    user_attr_map = {
        # 'user field': ('provider field', 'mutable by user')
        'identifier': ('uuid', False),
        'email': ('email', True),
        'first_name': ('first_name', True),
        'last_name': ('last_name', True),
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def update_last_login_at(self):
        instance = self._instance
        user = instance.user.__class__.objects.get(pk=instance.user.pk)
        date = datetime.now()
        instance.last_login_at = user.last_login = date
        instance.save()
        user.save()

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        # db lock
        objects = self.user.__class__.objects
        self.user = objects.select_for_update().get(pk=self.user.pk)

        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_active_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy", group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.base_project and user.base_project.delete()
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    tpl = smart_unicode(msg)
                    self.message_tpls_compiled[key] = tpl.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError:
                    continue
        else:
            params.update(self.message_tpls_compiled)

        for key, value in self.urls.iteritems():
            params['%s_url' % key] = value

        if self.user and self.resolve_available_methods:
            available_providers = self.user.get_enabled_auth_providers()
            for p in available_providers:
                p.resolve_available_methods = False
                if p.module == self.module and p.identifier == self.identifier:
                    available_providers.remove(p)

            get_msg = lambda p: p.get_method_prompt_msg
            params['available_methods'] = \
                ','.join(map(get_msg, available_providers))

            get_msg = lambda p: "<a href='%s'>%s</a>" % \
                (p.get_login_url, p.get_method_prompt_msg)

            params['available_methods_links'] = \
                ','.join(map(get_msg, available_providers))

        params.update(extra_params)
        return params

    def get_template(self, tpl):
        tpls = [
            'im/auth/%s_%s.html' % (self.module, tpl),
            getattr(self, '%s_template' % tpl)
        ]
        found = None
        for tpl in tpls:
            try:
                found = template.loader.get_template(tpl)
                return tpl
            except template.TemplateDoesNotExist:
                continue
        if not found:
            raise template.TemplateDoesNotExist
        return tpl

    def get_username(self):
        return self.get_username_msg

    def get_user_providers(self):
        return self.user.auth_providers.filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_active_providers(self):
        return self.user.auth_providers.active().filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_module_providers(self):
        return self.user.auth_providers.filter(module=self.module)

    def get_user_module_active_providers(self):
        return self.user.auth_providers.active().filter(module=self.module)

    def get_existing_providers(self):
        return ""

    def verified_exists(self):
        return self.get_provider_model().objects.verified(
            self.module, identifier=self.identifier)

    def resolve_policy(self, policy, default=None):

        if policy == 'switch' and default and not self.get_add_policy:
            return not self.get_policy('remove')

        if not self.user:
            return default

        if policy == 'remove' and default is True:
            return self.get_user_active_providers().count() > 1

        if policy == 'add' and default is True:
            limit = self.get_policy('limit')
            if limit <= self.get_user_module_active_providers().count():
                return False

            if self.identifier:
                if self.verified_exists():
                    return False

        return default

    def get_user_policies(self):
        from astakos.im.models import AuthProviderPolicyProfile
        return AuthProviderPolicyProfile.objects.for_user(
            self.user, self.module)

    def get_user_attr_map(self):
        """Get the mapping of provider to user attributes."""
        attr_map = self.user_attr_map
        settings_key = "USER_ATTR_MAP"
        settings_default = self.get_setting(settings_key, attr_map)
        attr_map.update(settings_default)
        return attr_map

    def get_provider_forced_attributes(self):
        """List of attributes that are automatically set by the provider."""
        attr_map = self.get_user_attr_map()
        return [
            attr for attr, (provider_attr, mutable) in attr_map.items()
            if not mutable
        ]

    def get_provider_info_attributes(self):
        """List of providers attributes to be stored in Astakos DB.

        Get list of provider's attributes that will be stored in Astakos DB
        in the 'info_data' field.

        """
        return self.get_setting("PROVIDER_ATTRS", [])

    def get_policy(self, policy):
        module_default = self.module_policies.get(policy)
        settings_key = '%s_POLICY' % policy.upper()
        settings_default = self.get_setting(settings_key, module_default)

        if self.user:
            user_policies = self.get_user_policies()
            settings_default = user_policies.get(policy, settings_default)

        return self.resolve_policy(policy, settings_default)

    def get_message(self, msg, **extra_params):
        """
        Retrieve an auth provider message
        """
        if msg.endswith('_msg'):
            msg = msg.replace('_msg', '')
        params = self._message_params(**extra_params)

        # is message ???
        tpl = self.message_tpls_compiled.get(msg.lower(), None)
        if not tpl:
            msg_key = 'AUTH_PROVIDER_%s' % msg.upper()
            try:
                tpl = getattr(astakos_messages, msg_key)
            except AttributeError:
                try:
                    msg_key = msg.upper()
                    tpl = getattr(astakos_messages, msg_key)
                except AttributeError:
                    tpl = ''

        in_settings = self.get_setting(msg)
        if in_settings:
            tpl = in_settings

        return tpl.format(**params)

    @property
    def urls(self):
        urls = {
            'login': reverse(self.login_view),
            'add': reverse(self.login_view),
            'profile': reverse('edit_profile'),
        }
        if self.user:
            urls.update({
                'resend_activation':
                self.user.get_resend_activation_url(),
            })
        if self.identifier and self._instance:
            urls.update({
                'switch':
                reverse(self.login_view) +
                '?switch_from=%d' % self._instance.pk,
                'remove':
                reverse('remove_auth_provider',
                        kwargs={'pk': self._instance.pk})
            })
        urls.update(self.module_urls)
        return urls

    def get_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDER_%s_%s' % (self.module.upper(),
                                                name.upper())

    def get_global_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDERS_%s' % name.upper()

    def has_global_setting(self, name):
        return hasattr(settings, self.get_global_setting_key(name))

    def has_setting(self, name):
        return hasattr(settings, self.get_setting_key(name))

    def get_setting(self, name, default=None):
        attr = self.get_setting_key(name)
        if not self.has_setting(name):
            return self.get_global_setting(name, default)
        return getattr(settings, attr, default)

    def get_global_setting(self, name, default=None):
        attr = self.get_global_setting_key(name)
        if not self.has_global_setting(name):
            return default
        return getattr(settings, attr, default)

    @property
    def provider_details(self):
        if self._provider_details:
            return self._provider_details

        self._provider_details = {}

        if self._instance:
            self._provider_details = self._instance.__dict__

        if self.user and self.identifier:
            if self.identifier:
                try:
                    self._provider_details = \
                        self.user.get_auth_providers().get(
                            module=self.module,
                            identifier=self.identifier).__dict__
                except Exception:
                    return {}
        return self._provider_details

    def __getattr__(self, key):
        if not key.startswith('get_'):
            return super(AuthProvider, self).__getattribute__(key)

        key = key.replace('get_', '')
        if key.endswith('_msg'):
            return self.get_message(key)

        if key.endswith('_policy'):
            return self.get_policy(key.replace('_policy', ''))

        if key.endswith('_url'):
            key = key.replace('_url', '')
            return self.urls.get(key)

        if key.endswith('_icon'):
            key = key.replace('_msg', '_icon')
            return settings.MEDIA_URL + self.get_message(key)

        if key.endswith('_setting'):
            key = key.replace('_setting', '')
            return self.get_message(key)

        if key.endswith('_template'):
            key = key.replace('_template', '')
            return self.get_template(key)

        return super(AuthProvider, self).__getattribute__(key)

    def is_active(self):
        return self.module_enabled

    @property
    def log_display(self):
        dsp = "%sAuth" % self.module.title()
        if self.user:
            dsp += "[%s]" % self.user.log_display
            if self.identifier:
                dsp += '[%s]' % self.identifier
                if self._instance and self._instance.pk:
                    dsp += '[%d]' % self._instance.pk
        return dsp

    def log(self, msg, *args, **kwargs):
        level = kwargs.pop('level', logging.INFO)
        message = '%s: %s' % (self.log_display, msg)
        logger.log(level, message, *args, **kwargs)
示例#4
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict((
        ('title', '{module_title}'),
        ('login_title', '{title} LOGIN'),
        ('method_prompt', '{title} login'),
        ('account_prompt', '{title} account'),
        ('signup_title', '{title}'),
        ('profile_title', '{title}'),
        ('method_details', '{account_prompt}: {identifier}'),
        ('primary_login_prompt', 'Login using {account_prompt}'),
        ('required', '{title} is required. You can assign it '
                     'from your profile page'),
        ('login_prompt', ''),
        ('add_prompt', 'Allows you to login using {title}'),
        ('login_extra', ''),
        ('username', '{username}'),
        ('disabled_for_create', 'It seems this is the first time you\'re '
                                'trying to access {service_name}. '
                                'Unfortunately, we are not accepting new '
                                'users at this point.'),
        ('switch_success', 'Account changed successfully.'),
        ('cannot_login', '{title} is not available for login. '
                         'Please use one of your other available methods '
                         'to login ({available_methods_links}'),

        # icons should end with _icon
        ('module_medium_icon', 'im/auth/icons-medium/{module}.png'),
        ('module_icon', 'im/auth/icons/{module}.png'))
    )

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = 'im/auth/generic_primary_login.html'
    login_template = 'im/auth/generic_login.html'
    signup_template = 'im/signup.html'
    login_prompt_template = 'im/auth/generic_login_prompt.html'
    signup_prompt_template = 'im/auth/signup_prompt.html'

    default_policies = {
        'login': True,
        'create': True,
        'add': True,
        'remove': True,
        'limit': 1,
        'switch': True,
        'add_groups': [],
        'creation_groups': [],
        'mirror_groups': False,  # Currently used only by LDAP
        'required': False,
        'autoverify': False,
        'automoderate': not astakos_settings.MODERATION_ENABLED
    }

    # Mapping of provider's attributes to attributes of AstakosUser.
    # The second element of the tuple dictates whether the attribute can be
    # changed by the user or is automatically set by the provider in every
    # login.
    # Identifier is used to get the unique user identifier of the third
    # party provider!
    user_attr_map = {
        # 'user field': ('provider field', 'mutable by user')
        'identifier': ('uuid', False),
        'email': ('email', True),
        'first_name': ('first_name', True),
        'last_name': ('last_name', True),
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, 'pk') and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if 'instance' in provider_params:
            self._instance = provider_params['instance']
            del provider_params['instance']

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider
        return AuthProvider

    def update_last_login_at(self):
        instance = self._instance
        user = instance.user.__class__.objects.get(pk=instance.user.pk)
        date = datetime.now()
        instance.last_login_at = user.last_login = date
        instance.save()
        user.save()

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log('removed from group due to add_groups_policy %s',
                     group.name)

        self._instance.delete()
        self.log('removed')

    def add_to_user(self, **params):
        # db lock
        objects = self.user.__class__.objects
        self.user = objects.select_for_update().get(pk=self.user.pk)

        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_active_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy",
                         group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy",
                     group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(
                self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)",
                            user.log_display)
                user.base_project and user.base_project.delete()
                user.delete()

        create_params = {
            'module': self.module,
            'info_data': json.dumps(self.provider_details.get('info', {})),
            'active': True,
            'identifier': self.identifier
        }
        if 'info' in self.provider_details:
            del self.provider_details['info']

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += ' (user: %r)' % self.user
        if self.identifier:
            r += '(identifier: %r)' % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {'module': self.module, 'module_title': self.module.title()}
        if self.identifier:
            params['identifier'] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if 'info' in self.provider_details:
                if isinstance(self.provider_details['info'], basestring):
                    self.provider_details['info'] = \
                        json.loads(self.provider_details['info'])
                for key, val in self.provider_details['info'].iteritems():
                    params['provider_info_%s' % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params['username'] = params[self.username_key]
        else:
            params['username'] = self.identifier

        branding_params = dict(
            map(lambda k: (k[0].lower(), k[1]),
                branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    tpl = smart_unicode(msg)
                    self.message_tpls_compiled[key] = tpl.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError:
                    continue
        else:
            params.update(self.message_tpls_compiled)

        for key, value in self.urls.iteritems():
            params['%s_url' % key] = value

        if self.user and self.resolve_available_methods:
            available_providers = self.user.get_enabled_auth_providers()
            for p in available_providers:
                p.resolve_available_methods = False
                if p.module == self.module and p.identifier == self.identifier:
                    available_providers.remove(p)

            get_msg = lambda p: p.get_method_prompt_msg
            params['available_methods'] = \
                ','.join(map(get_msg, available_providers))

            get_msg = lambda p: "<a href='%s'>%s</a>" % \
                (p.get_login_url, p.get_method_prompt_msg)

            params['available_methods_links'] = \
                ','.join(map(get_msg, available_providers))

        params.update(extra_params)
        return params

    def get_template(self, tpl):
        tpls = ['im/auth/%s_%s.html' % (self.module, tpl),
                getattr(self, '%s_template' % tpl)]
        found = None
        for tpl in tpls:
            try:
                found = template.loader.get_template(tpl)
                return tpl
            except template.TemplateDoesNotExist:
                continue
        if not found:
            raise template.TemplateDoesNotExist
        return tpl

    def get_username(self):
        return self.get_username_msg

    def get_user_providers(self):
        return self.user.auth_providers.filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_active_providers(self):
        return self.user.auth_providers.active().filter(
            module__in=astakos_settings.IM_MODULES)

    def get_user_module_providers(self):
        return self.user.auth_providers.filter(module=self.module)

    def get_user_module_active_providers(self):
        return self.user.auth_providers.active().filter(module=self.module)

    def get_existing_providers(self):
        return ""

    def verified_exists(self):
        return self.get_provider_model().objects.verified(
            self.module, identifier=self.identifier)

    def resolve_policy(self, policy, default=None):

        if policy == 'switch' and default and not self.get_add_policy:
            return not self.get_policy('remove')

        if not self.user:
            return default

        if policy == 'remove' and default is True:
            return self.get_user_active_providers().count() > 1

        if policy == 'add' and default is True:
            limit = self.get_policy('limit')
            if limit <= self.get_user_module_active_providers().count():
                return False

            if self.identifier:
                if self.verified_exists():
                    return False

        return default

    def get_user_policies(self):
        from astakos.im.models import AuthProviderPolicyProfile
        return AuthProviderPolicyProfile.objects.for_user(self.user,
                                                          self.module)

    def get_user_attr_map(self):
        """Get the mapping of provider to user attributes."""
        attr_map = self.user_attr_map
        settings_key = "USER_ATTR_MAP"
        settings_default = self.get_setting(settings_key, attr_map)
        attr_map.update(settings_default)
        return attr_map

    def get_provider_forced_attributes(self):
        """List of attributes that are automatically set by the provider."""
        attr_map = self.get_user_attr_map()
        return [attr
                for attr, (provider_attr, mutable) in attr_map.items()
                if not mutable]

    def get_provider_info_attributes(self):
        """List of providers attributes to be stored in Astakos DB.

        Get list of provider's attributes that will be stored in Astakos DB
        in the 'info_data' field.

        """
        return self.get_setting("PROVIDER_ATTRS", [])


    def get_policy(self, policy):
        module_default = self.module_policies.get(policy)
        settings_key = '%s_POLICY' % policy.upper()
        settings_default = self.get_setting(settings_key, module_default)

        if self.user:
            user_policies = self.get_user_policies()
            settings_default = user_policies.get(policy, settings_default)

        return self.resolve_policy(policy, settings_default)

    def get_message(self, msg, **extra_params):
        """
        Retrieve an auth provider message
        """
        if msg.endswith('_msg'):
            msg = msg.replace('_msg', '')
        params = self._message_params(**extra_params)

        # is message ???
        tpl = self.message_tpls_compiled.get(msg.lower(), None)
        if not tpl:
            msg_key = 'AUTH_PROVIDER_%s' % msg.upper()
            try:
                tpl = getattr(astakos_messages, msg_key)
            except AttributeError:
                try:
                    msg_key = msg.upper()
                    tpl = getattr(astakos_messages, msg_key)
                except AttributeError:
                    tpl = ''

        in_settings = self.get_setting(msg)
        if in_settings:
            tpl = in_settings

        return tpl.format(**params)

    @property
    def urls(self):
        urls = {
            'login': reverse(self.login_view),
            'add': reverse(self.login_view),
            'profile': reverse('edit_profile'),
        }
        if self.user:
            urls.update({
                'resend_activation': self.user.get_resend_activation_url(),
            })
        if self.identifier and self._instance:
            urls.update({
                'switch': reverse(self.login_view) + '?switch_from=%d' %
                self._instance.pk,
                'remove': reverse('remove_auth_provider',
                                  kwargs={'pk': self._instance.pk})
            })
        urls.update(self.module_urls)
        return urls

    def get_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDER_%s_%s' % (self.module.upper(),
                                                name.upper())

    def get_global_setting_key(self, name):
        return 'ASTAKOS_AUTH_PROVIDERS_%s' % name.upper()

    def has_global_setting(self, name):
        return hasattr(settings, self.get_global_setting_key(name))

    def has_setting(self, name):
        return hasattr(settings, self.get_setting_key(name))

    def get_setting(self, name, default=None):
        attr = self.get_setting_key(name)
        if not self.has_setting(name):
            return self.get_global_setting(name, default)
        return getattr(settings, attr, default)

    def get_global_setting(self, name, default=None):
        attr = self.get_global_setting_key(name)
        if not self.has_global_setting(name):
            return default
        return getattr(settings, attr, default)

    @property
    def provider_details(self):
        if self._provider_details:
            return self._provider_details

        self._provider_details = {}

        if self._instance:
            self._provider_details = self._instance.__dict__

        if self.user and self.identifier:
            if self.identifier:
                try:
                    self._provider_details = \
                        self.user.get_auth_providers().get(
                            module=self.module,
                            identifier=self.identifier).__dict__
                except Exception:
                    return {}
        return self._provider_details

    def __getattr__(self, key):
        if not key.startswith('get_'):
            return super(AuthProvider, self).__getattribute__(key)

        key = key.replace('get_', '')
        if key.endswith('_msg'):
            return self.get_message(key)

        if key.endswith('_policy'):
            return self.get_policy(key.replace('_policy', ''))

        if key.endswith('_url'):
            key = key.replace('_url', '')
            return self.urls.get(key)

        if key.endswith('_icon'):
            key = key.replace('_msg', '_icon')
            return settings.MEDIA_URL + self.get_message(key)

        if key.endswith('_setting'):
            key = key.replace('_setting', '')
            return self.get_message(key)

        if key.endswith('_template'):
            key = key.replace('_template', '')
            return self.get_template(key)

        return super(AuthProvider, self).__getattribute__(key)

    def is_active(self):
        return self.module_enabled

    @property
    def log_display(self):
        dsp = "%sAuth" % self.module.title()
        if self.user:
            dsp += "[%s]" % self.user.log_display
            if self.identifier:
                dsp += '[%s]' % self.identifier
                if self._instance and self._instance.pk:
                    dsp += '[%d]' % self._instance.pk
        return dsp

    def log(self, msg, *args, **kwargs):
        level = kwargs.pop('level', logging.INFO)
        message = '%s: %s' % (self.log_display, msg)
        logger.log(level, message, *args, **kwargs)
示例#5
0
class AuthProvider(object):

    __metaclass__ = AuthProviderBase

    module = None
    module_enabled = False
    is_primary = False

    message_tpls = OrderedDict(
        (
            ("title", "{module_title}"),
            ("login_title", "{title} LOGIN"),
            ("method_prompt", "{title} login"),
            ("account_prompt", "{title} account"),
            ("signup_title", "{title}"),
            ("profile_title", "{title}"),
            ("method_details", "{account_prompt}: {identifier}"),
            ("primary_login_prompt", "Login using "),
            ("required", "{title} is required. You can assign it " "from your profile page"),
            ("login_prompt", ""),
            ("add_prompt", "Allows you to login using {title}"),
            ("login_extra", ""),
            ("username", "{username}"),
            (
                "disabled_for_create",
                "It seems this is the first time you're "
                "trying to access {service_name}. "
                "Unfortunately, we are not accepting new "
                "users at this point.",
            ),
            ("switch_success", "Account changed successfully."),
            (
                "cannot_login",
                "{title} is not available for login. "
                "Please use one of your other available methods "
                "to login ({available_methods_links}",
            ),
            # icons should end with _icon
            ("module_medium_icon", "im/auth/icons-medium/{module}.png"),
            ("module_icon", "im/auth/icons/{module}.png"),
        )
    )

    messages = {}
    module_urls = {}

    remote_authenticate = True
    remote_logout_url = None

    # templates
    primary_login_template = "im/auth/generic_primary_login.html"
    login_template = "im/auth/generic_login.html"
    signup_template = "im/signup.html"
    login_prompt_template = "im/auth/generic_login_prompt.html"
    signup_prompt_template = "im/auth/signup_prompt.html"

    default_policies = {
        "login": True,
        "create": True,
        "add": True,
        "remove": True,
        "limit": 1,
        "switch": True,
        "add_groups": [],
        "creation_groups": [],
        "required": False,
        "automoderate": not astakos_settings.MODERATION_ENABLED,
    }

    policies = {}

    def __init__(self, user=None, identifier=None, **provider_params):
        """
        3 ways to initialize (no args, user, user and identifier).

        no args: Used for anonymous unauthenticated users.
        >>> p = auth_providers.get_provider('local')
        >>> # check that global settings allows us to create a new account
        >>> # using `local` provider.
        >>> print p.is_available_for_create()

        user and identifier: Used to provide details about a user's specific
        login method.
        >>> p = auth_providers.get_provider('google', user,
        >>>                                 identifier='1421421')
        >>> # provider (google) details prompt
        >>> print p.get_method_details()
        "Google account: 1421421"
        """

        # handle AnonymousUser instance
        self.user = None
        if user and hasattr(user, "pk") and user.pk:
            self.user = user

        self.identifier = identifier
        self._instance = None
        if "instance" in provider_params:
            self._instance = provider_params["instance"]
            del provider_params["instance"]

        # initialize policies
        self.module_policies = copy.copy(self.default_policies)
        self.module_policies["automoderate"] = not astakos_settings.MODERATION_ENABLED
        for policy, value in self.policies.iteritems():
            setting_key = "%s_POLICY" % policy.upper()
            if self.has_setting(setting_key):
                self.module_policies[policy] = self.get_setting(setting_key)
            else:
                self.module_policies[policy] = value

        # messages cache
        self.message_tpls_compiled = OrderedDict()

        # module specific messages
        self.message_tpls = OrderedDict(self.message_tpls)
        for key, value in self.messages.iteritems():
            self.message_tpls[key] = value

        self._provider_details = provider_params

        self.resolve_available_methods = True

    def get_provider_model(self):
        from astakos.im.models import AstakosUserAuthProvider as AuthProvider

        return AuthProvider

    def remove_from_user(self):
        if not self.get_remove_policy:
            raise Exception("Provider cannot be removed")

        for group_name in self.get_add_groups_policy:
            group = Group.objects.get(name=group_name)
            self.user.groups.remove(group)
            self.log("removed from group due to add_groups_policy %s", group.name)

        self._instance.delete()
        self.log("removed")

    def add_to_user(self, **params):
        if self._instance:
            raise Exception("Cannot add an existing provider")

        create = False
        if self.get_user_providers().count() == 0:
            create = True

        if create and not self.get_create_policy:
            raise Exception("Provider not available for create")

        if not self.get_add_policy:
            raise Exception("Provider cannot be added")

        if create:
            for group_name in self.get_creation_groups_policy:
                group, created = Group.objects.get_or_create(name=group_name)
                self.user.groups.add(group)
                self.log("added to %s group due to creation_groups_policy", group_name)

        for group_name in self.get_add_groups_policy:
            group, created = Group.objects.get_or_create(name=group_name)
            self.user.groups.add(group)
            self.log("added to %s group due to add_groups_policy", group_name)

        if self.identifier:
            pending = self.get_provider_model().objects.unverified(self.module, identifier=self.identifier)

            if pending:
                user = pending._instance.user
                logger.info("Removing existing unverified user (%r)", user.log_display)
                user.delete()

        create_params = {
            "module": self.module,
            "info_data": json.dumps(self.provider_details.get("info", {})),
            "active": True,
            "identifier": self.identifier,
        }
        if "info" in self.provider_details:
            del self.provider_details["info"]

        create_params.update(self.provider_details)
        create_params.update(params)
        create = self.user.auth_providers.create(**create_params)
        self.log("created %r" % create_params)
        return create

    def __repr__(self):
        r = "'%r' module" % self.__class__.__name__
        if self.user:
            r += " (user: %r)" % self.user
        if self.identifier:
            r += "(identifier: %r)" % self.identifier
        return r

    def _message_params(self, **extra_params):
        """
        Retrieve message formating parameters.
        """
        params = {"module": self.module, "module_title": self.module.title()}
        if self.identifier:
            params["identifier"] = self.identifier

        if self.user:
            for key, val in self.user.__dict__.iteritems():
                params["user_%s" % key.lower()] = val

        if self.provider_details:
            for key, val in self.provider_details.iteritems():
                params["provider_%s" % key.lower()] = val

            if "info" in self.provider_details:
                if isinstance(self.provider_details["info"], basestring):
                    self.provider_details["info"] = json.loads(self.provider_details["info"])
                for key, val in self.provider_details["info"].iteritems():
                    params["provider_info_%s" % key.lower()] = val

        # resolve username, handle unexisting defined username key
        if self.user and self.username_key in params:
            params["username"] = params[self.username_key]
        else:
            params["username"] = self.identifier

        branding_params = dict(map(lambda k: (k[0].lower(), k[1]), branding_utils.get_branding_dict().iteritems()))
        params.update(branding_params)

        if not self.message_tpls_compiled:
            for key, message_tpl in self.message_tpls.iteritems():
                msg = self.messages.get(key, self.message_tpls.get(key))
                override_in_settings = self.get_setting(key)
                if override_in_settings is not None:
                    msg = override_in_settings
                try:
                    self.message_tpls_compiled[key] = msg.format(**params)
                    params.update(self.message_tpls_compiled)
                except KeyError, e:
                    continue
        else: