예제 #1
0
 def perform_destroy(self, instance):
     # We will archive the user record to keep audit foreign keys
     # in place but we delete the roles on organizations
     # for that user to make sure access rights for the archive profile
     # are fully gone.
     get_role_model().objects.filter(user=instance).delete()
     super(UserProfileAPIView, self).perform_destroy(instance)
예제 #2
0
 def _wrapped_view(request, *args, **kwargs):
     LOGGER.debug("Enters djaoapp.decorators.requires_authenticated")
     redirect_url = fail_authenticated(request)
     if redirect_url:
         verification_key = kwargs.get('verification_key', None)
         if verification_key:
             contact = Contact.objects.filter(
                 verification_key=verification_key).first()
             if not contact:
                 # Not a `Contact`, let's try `Role`.
                 role_model = get_role_model()
                 try:
                     role = role_model.objects.filter(
                         Q(grant_key=verification_key)
                         | Q(request_key=verification_key)).get()
                     contact, _ = Contact.objects.update_or_create_token(
                         role.user)
                     verification_key = contact.verification_key
                 except role_model.DoesNotExist:
                     pass
             if contact and has_invalid_password(contact.user):
                 redirect_url = request.build_absolute_uri(
                     reverse('registration_activate',
                             args=(verification_key, )))
         return redirect_or_denied(
             request,
             redirect_url,
             redirect_field_name=redirect_field_name)
     return view_func(request, *args, **kwargs)
예제 #3
0
def user_activated_notice(sender, user, verification_key, request, **kwargs):
    """
    A new user has activated his account. We have a complete profile
    and active email address now.
    """
    for role in get_role_model().objects.filter(grant_key=verification_key):
        role.grant_key = None
        role.save()

    broker = get_broker()
    site = get_current_site()
    recipients, bcc = _notified_recipients(broker)
    app = get_current_app()
    LOGGER.debug(
        "[signal] user_activated_notice(user=%s, verification_key=%s)", user,
        verification_key)
    if SEND_EMAIL:
        get_email_backend(connection=app.get_connection()).send(
            from_email=app.get_from_email(),
            recipients=recipients,
            bcc=bcc,
            template='notification/user_activated.eml',
            context={
                'request': request,
                'broker': get_broker(),
                'app': app,
                'user': get_user_context(user),
                'urls': {
                    'user': {
                        'profile':
                        site.as_absolute_uri(
                            reverse('users_profile', args=(user, )))
                    }
                }
            })
예제 #4
0
def fail_authenticated(request, verification_key=None):
    """
    Decorator for views that checks that the user is authenticated.

    ``django.contrib.auth.decorators.login_required`` will automatically
    redirect to the login page. We wante to redirect to the activation
    page when required, as well as raise a ``PermissionDenied``
    instead when Content-Type is showing we are dealing with an API request.
    """
    redirect = fail_authenticated_default(request)
    if redirect:
        if verification_key:
            contact = Contact.objects.filter(
                verification_key=verification_key).first()
            if not contact:
                # Not a `Contact`, let's try `Role`.
                role_model = get_role_model()
                try:
                    role = role_model.objects.filter(
                        Q(grant_key=verification_key)
                        | Q(request_key=verification_key)).get()
                    contact, _ = Contact.objects.update_or_create_token(
                        role.user)
                    verification_key = contact.verification_key
                except role_model.DoesNotExist:
                    pass
            if contact and has_invalid_password(contact.user):
                redirect = request.build_absolute_uri(
                    reverse('registration_activate',
                            args=(verification_key, )))
    return redirect
예제 #5
0
class RoleListAPIView(RoleListBaseAPIView):
    """
    Lists roles of a specific type

    Lists the specified role assignments for an organization.

    **Tags: rbac

    **Examples

    .. code-block:: http

        GET /api/profile/cowork/roles/manager/ HTTP/1.1

    responds

    .. code-block:: json

        {
            "count": 1,
            "next": null,
            "previous": null,
            "results": [
                {
                    "created_at": "2018-01-01T00:00:00Z",
                    "role_description": {
                        "name": "Manager",
                        "slug": "manager",
                        "organization": {
                            "slug": "cowork",
                            "full_name": "ABC Corp.",
                            "printable_name": "ABC Corp.",
                            "created_at": "2018-01-01T00:00:00Z",
                            "email": "*****@*****.**"
                        }
                    },
                    "user": {
                        "slug": "alice",
                        "email": "*****@*****.**",
                        "full_name": "Alice Doe",
                        "created_at": "2018-01-01T00:00:00Z"
                    },
                    "request_key": "1",
                    "grant_key": null
                }
            ]
        }
    """
    serializer_class = RoleSerializer
    queryset = get_role_model().objects.all().select_related('user__contact')
예제 #6
0
def fail_active_roles(request):
    """
    User with active roles only
    """
    role_model = get_role_model()
    redirect_to = reverse('saas_user_product_list', args=(request.user, ))
    if request.path == redirect_to:
        # Prevents URL redirect loops
        return False

    if role_model.objects.filter(user=request.user,
                                 grant_key__isnull=False).exists():
        # We have some invites pending so let's first stop
        # by the user accessibles page.
        return redirect_to

    return False
예제 #7
0
def fail_authenticated(request, verification_key=None):
    """
    Decorator for views that checks that the user is authenticated.

    ``django.contrib.auth.decorators.login_required`` will automatically
    redirect to the login page. We wante to redirect to the activation
    page when required, as well as raise a ``PermissionDenied``
    instead when Content-Type is showing we are dealing with an API request.
    """
    try:
        app = get_current_app()
        #pylint:disable=unused-variable
        redirect, matched, session = check_matched(request,
                                                   app,
                                                   prefixes=DEFAULT_PREFIXES)
    except NoRuleMatch:
        redirect = fail_authenticated_default(request)
        if redirect:
            if verification_key:
                contact = Contact.objects.filter(
                    Q(email_verification_key=verification_key)
                    | Q(phone_verification_key=verification_key)).first()
                if not contact:
                    # Not a `Contact`, let's try `Role`.
                    role_model = get_role_model()
                    try:
                        role = role_model.objects.filter(
                            Q(grant_key=verification_key)
                            | Q(request_key=verification_key)).get()
                        contact, _ = Contact.objects.prepare_email_verification(
                            role.user, role.user.email)
                        verification_key = contact.email_verification_key
                    except role_model.DoesNotExist:
                        pass
                if contact and has_invalid_password(contact.user):
                    redirect = request.build_absolute_uri(
                        reverse('registration_activate',
                                args=(verification_key, )))
    return redirect
예제 #8
0
def inject_edition_tools(response,
                         request,
                         context=None,
                         body_top_template_name=None,
                         body_bottom_template_name=None):
    """
    If the ``request.user`` has editable permissions, this method
    injects the edition tools into the html *content* and return
    a BeautifulSoup object of the resulting content + tools.

    If the response is editable according to the proxy rules, this
    method returns a BeautifulSoup object of the content such that
    ``PageMixin`` inserts the edited page elements.
    """
    #pylint:disable=too-many-locals,too-many-nested-blocks,too-many-statements
    content_type = response.get('content-type', '')
    if not content_type.startswith('text/html'):
        return None

    if not is_authenticated(request):
        return None

    if context is None:
        context = {}

    # ``app.account`` is guarenteed to be in the same database as ``app``.
    # ``site.account`` is always in the *default* database, which is not
    # the expected database ``Organization`` are typically queried from.
    app = get_current_app()
    provider = app.account
    soup = None
    if app.show_edit_tools and get_role_model().objects.valid_for(
            organization=provider, user=request.user):
        edit_urls = {
            'api_medias':
            reverse('uploaded_media_elements', kwargs={'path': ''}),
            'api_sitecss':
            reverse('edit_sitecss'),
            'api_less_overrides':
            reverse('pages_api_less_overrides'),
            'api_sources':
            reverse('pages_api_sources'),
            'api_page_element_base':
            reverse('api_page_element', kwargs={'path': ''}),
            'api_plans':
            reverse('saas_api_plans', args=(provider, )),
            'plan_update_base':
            reverse('saas_plan_base', args=(provider, ))
        }
        try:
            # The following statement will raise an Exception
            # when we are dealing with a ``FileSystemStorage``.
            _ = get_storage_class().bucket_name
            edit_urls.update(
                {'media_upload': reverse('api_credentials_organization')})
        except AttributeError:
            LOGGER.debug("doesn't look like we have a S3Storage.")
        # XXX sites which are hosted on a same domain shouldn't disable
        # all edit functionality, just the edition of base templates.
        site = get_current_site()
        enable_code_editor = is_domain_site(site)
        if enable_code_editor:
            dj_urls = djaoapp_urls(request,
                                   account=provider,
                                   base=site.as_base())
            body_bottom_template_name = "pages/_body_bottom_edit_tools.html"
        else:
            dj_urls = djaoapp_urls(request, account=provider)
            body_bottom_template_name = "pages/_body_bottom.html"

        context.update({
            'ENABLE_CODE_EDITOR': enable_code_editor,
            'FEATURE_DEBUG': settings.FEATURES_DEBUG,
            'urls': {
                'djaodjin': dj_urls,
                'edit': edit_urls
            }
        })
        context.update(csrf(request))
        soup = pages_inject_edition_tools(
            response,
            request,
            context=context,
            body_top_template_name=body_top_template_name,
            body_bottom_template_name=body_bottom_template_name)

    # Insert the authenticated user information and roles on organization.
    if not soup:
        soup = BeautifulSoup(response.content, 'html5lib')
    if soup and soup.body:
        # Implementation Note: we have to use ``.body.next`` here
        # because html5lib "fixes" our HTML by adding missing
        # html/body tags. Furthermore if we use
        #``soup.body.insert(1, BeautifulSoup(body_top, 'html.parser'))``
        # instead, later on ``soup.find_all(class_=...)`` returns
        # an empty set though ``soup.prettify()`` outputs the full
        # expected HTML text.
        auth_user = soup.body.find(class_='header-menubar')
        user_menu_template = '_menubar.html'
        if auth_user and user_menu_template:
            serializer_class = import_string(rules_settings.SESSION_SERIALIZER)
            serializer = serializer_class(request)
            path_parts = reversed(request.path.split('/'))
            top_accessibles = []
            has_broker_role = False
            active_organization = None
            for role, organizations in six.iteritems(serializer.data['roles']):
                for organization in organizations:
                    if organization['slug'] == request.user.username:
                        # Personal Organization
                        continue
                    db_obj = get_organization_model().objects.get(
                        slug=organization['slug'])  # XXX Remove query.
                    if db_obj.is_provider:
                        settings_location = reverse(
                            'saas_dashboard', args=(organization['slug'], ))
                    else:
                        settings_location = reverse(
                            'saas_organization_profile',
                            args=(organization['slug'], ))
                    app_location = reverse('organization_app',
                                           args=(organization['slug'], ))
                    if organization['slug'] in path_parts:
                        active_organization = TopAccessibleOrganization(
                            organization['slug'],
                            organization['printable_name'], settings_location,
                            role, app_location)
                    if is_broker(organization['slug']):
                        has_broker_role = True
                    top_accessibles += [
                        TopAccessibleOrganization(
                            organization['slug'],
                            organization['printable_name'], settings_location,
                            role, app_location)
                    ]
            if not active_organization and has_broker_role:
                active_organization = get_broker()
            context.update({'active_organization': active_organization})
            context.update({'top_accessibles': top_accessibles})
            template = loader.get_template(user_menu_template)
            user_menu = render_template(template, context, request).strip()
            auth_user.clear()
            els = BeautifulSoup(user_menu, 'html5lib').body.ul.children
            for elem in els:
                auth_user.append(BeautifulSoup(str(elem), 'html5lib'))

    return soup