Exemple #1
0
def ensure_valid(
    strategy,
    backend,
    user,
    registering_user,
    weblate_action,
    weblate_expires,
    new_association,
    details,
    **kwargs,
):
    """Ensure the activation link is still."""
    # Didn't the link expire?
    if weblate_expires < time.time():
        raise AuthMissingParameter(backend, "expires")

    # We allow password reset for unauthenticated users
    if weblate_action == "reset":
        if strategy.request.user.is_authenticated:
            messages.warning(
                strategy.request,
                _("You can not complete password reset while signed in."),
            )
            messages.warning(strategy.request,
                             _("The registration link has been invalidated."))
            raise AuthMissingParameter(backend, "user")
        return

    # Add e-mail/register should stay on same user
    if user and user.is_authenticated:
        current_user = user.pk
    else:
        current_user = None

    if current_user != registering_user:
        if registering_user is None:
            messages.warning(
                strategy.request,
                _("You can not complete registration while signed in."),
            )
        else:
            messages.warning(
                strategy.request,
                _("You can confirm your registration only while signed in."),
            )
        messages.warning(strategy.request,
                         _("The registration link has been invalidated."))

        raise AuthMissingParameter(backend, "user")

    # Verify if this mail is not used on other accounts
    if new_association:
        same = VerifiedEmail.objects.filter(email__iexact=details["email"])
        if user:
            same = same.exclude(social__user=user)

        if same.exists():
            AuditLog.objects.create(same[0].social.user, strategy.request,
                                    "connect")
            raise EmailAlreadyAssociated(backend, "E-mail exists")
Exemple #2
0
    def verify_data(self, response):
        bot_token = self.setting('BOT_TOKEN')
        if bot_token is None:
            raise AuthMissingParameter('telegram',
                                       'SOCIAL_AUTH_TELEGRAM_BOT_TOKEN')

        received_hash_string = response.get('hash')
        auth_date = response.get('auth_date')

        if received_hash_string is None or auth_date is None:
            raise AuthMissingParameter('telegram', 'hash or auth_date')

        data_check_string = [
            '{}={}'.format(k, v) for k, v in response.items() if k != 'hash'
        ]
        data_check_string = '\n'.join(sorted(data_check_string))
        secret_key = hashlib.sha256(bot_token.encode()).digest()
        built_hash = hmac.new(secret_key,
                              msg=data_check_string.encode(),
                              digestmod=hashlib.sha256).hexdigest()
        current_timestamp = int(time.time())
        auth_timestamp = int(auth_date)
        if current_timestamp - auth_timestamp > 86400:
            raise AuthFailed('telegram', 'Auth date is outdated')
        if built_hash != received_hash_string:
            raise AuthFailed('telegram', 'Invalid hash supplied')
Exemple #3
0
def verify_open(strategy, backend, user, weblate_action, **kwargs):
    """Check whether it is possible to create new user."""
    # Check whether registration is open
    if (not user and not settings.REGISTRATION_OPEN
            and weblate_action not in ('reset', 'remove', 'invite')):
        raise AuthMissingParameter(backend, 'disabled')

    # Ensure it's still same user
    request = strategy.request
    if request.user.pk != request.session.get('social_auth_user'):
        raise AuthMissingParameter(backend, 'user')
Exemple #4
0
def verify_open(strategy, backend, user=None, **kwargs):
    """Check whether it is possible to create new user."""
    # Check whether registration is open
    if not user and not settings.REGISTRATION_OPEN:
        raise AuthMissingParameter(backend, 'disabled')

    # Avoid adding associations to demo user
    if user and settings.DEMO_SERVER and user.username == 'demo':
        raise AuthMissingParameter(backend, 'demo')

    # Ensure it's still same user
    request = strategy.request
    if request.user.pk != request.session.get('social_auth_user'):
        raise AuthMissingParameter(backend, 'user')
Exemple #5
0
def verify_open(strategy, backend, user, weblate_action, **kwargs):
    """Check whether it is possible to create new user."""
    # Check whether registration is open
    if (not user and not settings.REGISTRATION_OPEN
            and weblate_action not in ("reset", "remove", "invite")):
        raise AuthMissingParameter(backend, "disabled")

    # Ensure it's still same user (if sessions was kept as this is to avoid
    # completing authentication under diferent user than initiated it, with
    # new session, it will complete as new user)
    current_user = strategy.request.user.pk
    init_user = strategy.request.session.get("social_auth_user")
    if strategy.request.session.session_key and current_user != init_user:
        raise AuthMissingParameter(backend, "user")
Exemple #6
0
def ensure_valid(strategy, backend, user, registering_user, weblate_action,
                 weblate_expires, new_association, details, **kwargs):
    """Ensure the activation link is still."""

    # Didn't the link expire?
    if weblate_expires < time.time():
        raise AuthMissingParameter(backend, 'expires')

    # We allow password reset for unauthenticated users
    if weblate_action == 'reset':
        if strategy.request.user.is_authenticated:
            messages.warning(
                strategy.request,
                _('You can not complete password reset while logged in!'))
            messages.warning(strategy.request,
                             _('The registration link has been invalidated.'))
            raise AuthMissingParameter(backend, 'user')
        return

    # Add email/register should stay on same user
    if user and user.is_authenticated:
        current_user = user.pk
    else:
        current_user = None

    if current_user != registering_user:
        if registering_user is None:
            messages.warning(
                strategy.request,
                _('You can not complete registration while logged in!'))
        else:
            messages.warning(
                strategy.request,
                _('You can confirm your registration only while logged in!'))
        messages.warning(strategy.request,
                         _('The registration link has been invalidated.'))

        raise AuthMissingParameter(backend, 'user')

    # Verify if this mail is not used on other accounts
    if new_association:
        same = VerifiedEmail.objects.filter(email=details['email'])
        if user:
            same = same.exclude(social__user=user)

        if same.exists():
            notify_account_activity(same[0].social.user, strategy.request,
                                    'connect')
            raise AuthAlreadyAssociated(backend, 'Email exists')
 def auth_complete(self, *args, **kwargs):
     """Completes loging process, must return user instance"""
     if 'connectData' not in self.data:
         raise AuthMissingParameter(self, self.ID_KEY)
     data = json.loads(base64.b64decode(self.data['connectData']).decode('utf-8'))
     kwargs.update({'response': data, 'backend': self})
     return self.strategy.authenticate(*args, **kwargs)
Exemple #8
0
def require_email(backend,
                  details,
                  weblate_action,
                  user=None,
                  is_new=False,
                  **kwargs):
    """Force entering email for backends which don't provide it."""

    if backend.name == 'github':
        email = get_github_email(kwargs['response']['access_token'])
        if email is not None:
            details['email'] = email

    # Remove any pending email validation codes
    if details.get('email') and backend.name == 'email':
        invalidate_reset_codes(emails=(details['email'], ))
        # Remove all account reset codes
        if user and weblate_action == 'reset':
            invalidate_reset_codes(user=user)

    if user and user.email:
        # Force validation of new email address
        if backend.name == 'email':
            return {'is_new': True}

        return None

    elif is_new and not details.get('email'):
        raise AuthMissingParameter(backend, 'email')
    return None
Exemple #9
0
def require_email(backend,
                  details,
                  weblate_action,
                  user=None,
                  is_new=False,
                  **kwargs):
    """Force entering e-mail for backends which don't provide it."""
    if backend.name == "github":
        email = get_github_email(kwargs["response"]["access_token"])
        if email is not None:
            details["email"] = email
        if details.get("email", "").endswith("@users.noreply.github.com"):
            del details["email"]

    # Remove any pending e-mail validation codes
    if details.get("email") and backend.name == "email":
        invalidate_reset_codes(emails=(details["email"], ))
        # Remove all account reset codes
        if user and weblate_action == "reset":
            invalidate_reset_codes(user=user)

    if user and user.email:
        # Force validation of new e-mail address
        if backend.name == "email":
            return {"is_new": True}

        return None

    if is_new and not details.get("email"):
        raise AuthMissingParameter(backend, "email")
    return None
 def validate_state(self):
     """Validate state value. Raises exception on error, returns state
     value if valid."""
     if not self.STATE_PARAMETER and not self.REDIRECT_STATE:
         return None
     state = self.get_session_state()
     request_state = self.get_request_state()
     #self.social_error_logger('Test Error Message.')
     if not request_state:
         self.errordesc = AuthMissingParameter(self, 'state').__str__()
         self.social_error_logger(self.errordesc)
         #raise AuthMissingParameter(self, 'state')
     elif not state:
         self.errordesc = 'Session value state missing.'
         self.social_error_logger(self.errordesc)
         #raise AuthStateMissing(self, 'state')
         # name = self.name + '_state'
         # state = self.data['state']
         # self.strategy.session_set(name, state)
         # state = self.get_session_state()
         # if not state:
         #     raise AuthStateMissing(self, 'state')
         # else: return state
     elif not request_state == state:
         self.errordesc = 'Wrong state parameter given'
         self.social_error_logger(self.errordesc)
         #raise AuthStateForbidden(self)
     else:
         return state
Exemple #11
0
    def auth_complete(self, *args, **kwargs):
        borrower_info = kwargs.get('borrower_info')
        if not borrower_info:
            raise AuthMissingParameter(self, 'borrower_info')

        kwargs.update({'response': borrower_info, 'backend': self})
        return self.strategy.authenticate(*args, **kwargs)
Exemple #12
0
def store_email(strategy, backend, user, social, details, **kwargs):
    """Store verified email."""
    if 'email' not in details or details['email'] is None:
        raise AuthMissingParameter(backend, 'email')
    verified, dummy = VerifiedEmail.objects.get_or_create(social=social)
    if verified.email != details['email']:
        verified.email = details['email']
        verified.save()
    def auth_complete(self, *args, **kwargs):
        """Completes loging process, must return user instance"""
        if 'connectData' not in self.data:
            raise AuthMissingParameter(self, 'connectData')
        response = json.loads(base64.b64decode(self.data['connectData']).decode('utf-8'))
        kwargs.update({'response': response, 'backend': self})

        return self.do_auth(response['token'], *args, **kwargs)
Exemple #14
0
    def auth_complete(self, *args, **kwargs):
        if 'SAMLResponse' not in self.data:
            raise AuthMissingParameter(self, 'SAMLResponse')
        if 'RelayState' not in self.data:
            raise AuthMissingParameter(self, 'RelayState')

        nonce = self.data['RelayState']
        nonce_obj = self.get_nonce(nonce)
        if not nonce_obj:
            raise AuthStateForbidden(self,
                                     'Invalid nonce in RelayState: %s' % nonce)

        # Remove the association object to prevent re-use attacks.
        self.remove_nonce(nonce_obj.id)

        request = self.strategy.request
        if not request.session.session_key and nonce_obj.secret:
            session = session_engine.SessionStore(nonce_obj.secret)
            request.session = self.strategy.session = session

        # FIXME: verify AuthCode

        resp = base64.b64decode(self.data['SAMLResponse']).decode('utf8')
        data = json.loads(resp)
        status_code = data.get('status_code', '')
        if status_code.lower() != 'success':
            auditlog.log_authentication_failure(request, self.name)
            raise AuthFailed(self,
                             'Authentication unsuccessful: %s' % status_code)

        oid = data.get('oid', '')
        if not oid:
            raise AuthMissingParameter(self, 'oid')

        auditlog.log_authentication_success(request, self.name, identifier=oid)

        response = {
            'oid': oid,
            'attributes': data.get('attributes', {}),
            'session_index': data.get('session_index', ''),
        }
        kwargs.update({'response': response, 'backend': self})
        return self.strategy.authenticate(*args, **kwargs)
Exemple #15
0
 def openid_url(self):
     """Return service provider URL.
     This base class is generic accepting a POST parameter that specifies
     provider URL."""
     if self.URL:
         return self.URL
     elif OPENID_ID_FIELD in self.data:
         return self.data[OPENID_ID_FIELD]
     elif self.strategy.session_get(OPENID_ID_FIELD, None):
         return self.strategy.session_get(OPENID_ID_FIELD, None)
     else:
         raise AuthMissingParameter(self, OPENID_ID_FIELD)
Exemple #16
0
def ensure_valid(strategy, backend, user, registering_user, weblate_action,
                 weblate_expires, **kwargs):
    """Ensure the activation link is still."""
    # Didn't the link expire?
    if weblate_expires < time.time():
        raise AuthMissingParameter(backend, 'expires')

    # We allow password reset for unauthenticated users
    if weblate_action == 'reset':
        if strategy.request.user.is_authenticated:
            messages.warning(
                strategy.request,
                _('You can not complete password reset while logged in!'))
            messages.warning(strategy.request,
                             _('The registration link has been invalidated.'))
            raise AuthMissingParameter(backend, 'user')
        return

    # Add email/register should stay on same user
    if user and user.is_authenticated:
        current_user = user.pk
    else:
        current_user = None

    if current_user != registering_user:
        if registering_user is None:
            messages.warning(
                strategy.request,
                _('You can not complete registration while logged in!'))
        else:
            messages.warning(
                strategy.request,
                _('You can confirm your registration only while logged in!'))
        messages.warning(strategy.request,
                         _('The registration link has been invalidated.'))

        raise AuthMissingParameter(backend, 'user')
Exemple #17
0
 def auth_complete(self, *args, **kwargs):
     """Completes loging process, must return user instance"""
     if self.ENV_USERNAME in os.environ:
         response = os.environ
     elif type(
             self.strategy
     ).__name__ == "DjangoStrategy" and self.ENV_USERNAME in self.strategy.request.META:
         # Looks like the Django strategy. In this case, it might by mod_wsgi, which stores
         # authentication environment variables in request.META
         response = self.strategy.request.META
     else:
         raise AuthMissingParameter(
             self,
             "%s, found only: %s" % (self.ENV_USERNAME, str(os.environ)))
     kwargs.update({'response': response, 'backend': self})
     return self.strategy.authenticate(*args, **kwargs)
 def auth_complete(self, *args, **kwargs):
     """
     Completes loging process, must return user instance.
     """
     if self.ID_KEY not in self.data:
         code = (self.strategy.request.GET.get('verification_code')
                 or self.strategy.request.POST.get('verification_code'))
         code_object = CustomCode.objects.filter(code=code,
                                                 verified=False).first()
         if code_object:
             email = code_object.email
             self.data.update({'email': email})
             if code_object.next_page:
                 self.data['next'] = code_object.next_page
                 self.strategy.session_set('next', code_object.next_page)
         else:
             raise AuthMissingParameter(self, self.ID_KEY)
     kwargs.update({'response': self.data, 'backend': self})
     return self.strategy.authenticate(*args, **kwargs)
Exemple #19
0
    def _get_attr(self,
                  response_attributes: Dict[str, Any],
                  attribute_names: List[str],
                  optional: bool = False) -> str:
        """
        Fetches a specific attribute from the SAML response, attempting with multiple different attribute names.
        We attempt multiple attribute names to make it easier for admins to configure SAML (less configuration to set).
        """
        output = None
        for _attr in attribute_names:
            if _attr in response_attributes:
                output = response_attributes[_attr]
                break

        if not output and not optional:
            raise AuthMissingParameter("saml", attribute_names[0])

        if isinstance(output, list):
            output = output[0]

        return output
Exemple #20
0
    def auth_url(self):
        """
        Overridden to use the config from the relevant OrganizationDomain
        Get the URL to which we must redirect in order to
        authenticate the user
        """
        email = self.strategy.request_data().get("email")

        if not email:
            raise AuthMissingParameter("saml", "email")

        instance = OrganizationDomain.objects.get_verified_for_email_address(
            email=email)

        if not instance or not instance.has_saml:
            raise AuthFailed("saml", "SAML not configured for this user.")

        auth = self._create_saml_auth(idp=self.get_idp(instance))
        # Below, return_to sets the RelayState, which contains the ID of
        # the `OrganizationDomain`.  We use it to store the specific SAML IdP
        # name, since we multiple IdPs share the same auth_complete URL.
        return auth.login(return_to=str(instance.id))
Exemple #21
0
    def get_user_id(self, *args, **kwargs):
        """
        Insert a slug at the beginning of the user id. Retroactively add the
        slug for social users that don't have one. The slug must be defined
        in the 'OTHER_SETTINGS' field from the provider configuration.
        In case a slug was not defined raise an exception due to misconfigured
        backend.
        This three behaviours can be controlled via the settings:
            - 'SOCIAL_AUTH_NAMESPACED_UIDS': if false behave as originally
            intended. If true, add a slug to the uid.
            - 'SOCIAL_AUTH_ALLOW_SLUGLESS_UID': if false raise and exception when no slug
            is defined. If true, return de original uid when no slug is defined.
            - 'SOCIAL_AUTH_ALLOW_WRITE_SLUG_UID': If true update the uid of existing social
            users if any.

        A first step to start migrating to name spaced uids would look like this:

        on the site settings:
        {
          "SOCIAL_AUTH_NAMESPACED_UIDS": true,
          "SOCIAL_AUTH_ALLOW_SLUGLESS_UID": true,
          "SOCIAL_AUTH_ALLOW_WRITE_SLUG_UID": true
        }

        on the provider configuration:
            OTHER_SETTINGS:
            {
              "slug": "myslug"
            }

        Setting 'SOCIAL_AUTH_NAMESPACED_UIDS' to true and adding the slug to
        'OTHER_SETTINGS' will create new associations with the new format.
        'SOCIAL_AUTH_ALLOW_WRITE_SLUG_UID'=true  will update older entries to the new
        format at login time and 'SOCIAL_AUTH_ALLOW_SLUGLESS_UID'=true would allow
        the previous format for older entries for the time being.

        Once all the old uids have been updated to the new format we can forbid the
        old format altogether and stop trying to updated uids without a slug.

        on the site settings:
        {
          "SOCIAL_AUTH_NAMESPACED_UIDS": true,
          "SOCIAL_AUTH_ALLOW_SLUGLESS_UID": false,
          "SOCIAL_AUTH_ALLOW_WRITE_SLUG_UID": false
        }

        on the provider configuration:
            OTHER_SETTINGS:
            {
              "slug": "myslug"
            }
        """
        uid = super().get_user_id(*args, **kwargs)
        namespaced_uids = self.setting('NAMESPACED_UIDS', False)
        if not namespaced_uids:
            return uid

        strategy = self.strategy
        slug = strategy.setting('slug', backend=self)
        provider = self.name
        allow_slugless_uid = self.setting('ALLOW_SLUGLESS_UID', False)
        allow_write_slug_uid = self.setting('ALLOW_WRITE_SLUG_UID', True)

        if not slug:
            if allow_slugless_uid:
                return uid
            raise AuthMissingParameter(self, 'slug')

        slug_uid = '{0}:{1}'.format(slug, uid)
        if allow_write_slug_uid:
            social = strategy.storage.user.get_social_auth(provider, uid)
            if social:
                social.uid = slug_uid
                social.save()
                LOG.info("Updating uid: %s to %s", uid, slug_uid)

        return slug_uid