web/admin: filter out service accounts by default

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-05-04 18:14:25 +02:00
parent a335ca0895
commit 0d370ef0a9
6 changed files with 82 additions and 8 deletions

View file

@ -22,7 +22,7 @@ lint:
bandit -r authentik tests lifecycle -x node_modules
pylint authentik tests lifecycle
gen: coverage
gen:
./manage.py generate_swagger -o swagger.yaml -f yaml
local-stack:
@ -31,7 +31,5 @@ local-stack:
docker-compose up -d
docker-compose run --rm server migrate
build-static:
docker-compose -f scripts/ci.docker-compose.yml up -d
docker build -t beryju/authentik-static -f static.Dockerfile --network=scripts_default .
docker-compose -f scripts/ci.docker-compose.yml down -v
run:
go run -v cmd/server/main.go

View file

@ -1,14 +1,18 @@
"""User API Views"""
from json import loads
from django.http.response import Http404
from django.urls import reverse_lazy
from django.utils.http import urlencode
from django_filters.filters import CharFilter
from django_filters.filterset import FilterSet
from drf_yasg.utils import swagger_auto_schema, swagger_serializer_method
from guardian.utils import get_anonymous_user
from rest_framework.decorators import action
from rest_framework.fields import CharField, JSONField, SerializerMethodField
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BooleanField, ModelSerializer
from rest_framework.serializers import BooleanField, ModelSerializer, ValidationError
from rest_framework.viewsets import ModelViewSet
from authentik.admin.api.metrics import CoordinateSerializer, get_events_per_1h
@ -84,13 +88,42 @@ class UserMetricsSerializer(PassiveSerializer):
)
class UsersFilter(FilterSet):
"""Filter for users"""
attributes = CharFilter(
field_name="attributes",
lookup_expr="",
label="Attributes",
method="filter_attributes",
)
# pylint: disable=unused-argument
def filter_attributes(self, queryset, name, value):
"""Filter attributes by query args"""
try:
value = loads(value)
except ValueError:
raise ValidationError(detail="filter: failed to parse JSON")
if not isinstance(value, dict):
raise ValidationError(detail="filter: value must be key:value mapping")
qs = {}
for key, _value in value.items():
qs[f"attributes__{key}"] = _value
return queryset.filter(**qs)
class Meta:
model = User
fields = ["username", "name", "is_active", "attributes"]
class UserViewSet(ModelViewSet):
"""User Viewset"""
queryset = User.objects.none()
serializer_class = UserSerializer
search_fields = ["username", "name", "is_active"]
filterset_fields = ["username", "name", "is_active"]
filterset_class = UsersFilter
def get_queryset(self):
return User.objects.all().exclude(pk=get_anonymous_user().pk)

View file

@ -1,6 +1,7 @@
package web
import (
"net/http"
"net/http/httputil"
"net/url"
)
@ -9,5 +10,11 @@ func (ws *WebServer) configureProxy() {
// Reverse proxy to the application server
u, _ := url.Parse("http://localhost:8000")
rp := httputil.NewSingleHostReverseProxy(u)
rp.ErrorHandler = ws.proxyErrorHandler
ws.m.PathPrefix("/").Handler(rp)
}
func (ws *WebServer) proxyErrorHandler(rw http.ResponseWriter, req *http.Request, err error) {
ws.log.WithError(err).Warning("proxy error")
rw.WriteHeader(http.StatusBadGateway)
}

View file

@ -1994,6 +1994,11 @@ paths:
description: ''
required: false
type: string
- name: attributes
in: query
description: ''
required: false
type: string
- name: ordering
in: query
description: Which field to use when ordering the results.

View file

@ -56,7 +56,7 @@ export class PlexSourceForm extends Form<PlexSource> {
};
async doAuth(): Promise<void> {
const authInfo = await PlexAPIClient.getPin(this.source?.clientId);
const authInfo = await PlexAPIClient.getPin(this.source?.clientId || "");
const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700);
PlexAPIClient.pinPoll(this.source?.clientId || "", authInfo.pin.id).then(token => {
authWindow?.close();

View file

@ -35,12 +35,18 @@ export class UserListPage extends TablePage<User> {
@property()
order = "last_login";
@property({ type: Boolean })
hideServiceAccounts = true;
apiEndpoint(page: number): Promise<AKResponse<User>> {
return new CoreApi(DEFAULT_CONFIG).coreUsersList({
ordering: this.order,
page: page,
pageSize: PAGE_SIZE,
search: this.search || "",
attributes: this.hideServiceAccounts ? JSON.stringify({
"goauthentik.io/user/service-account__isnull": "true"
}) : undefined
});
}
@ -163,4 +169,29 @@ export class UserListPage extends TablePage<User> {
`;
}
renderToolbarAfter(): TemplateResult {
return html`&nbsp;
<div class="pf-c-toolbar__group pf-m-filter-group">
<div class="pf-c-toolbar__item pf-m-search-filter">
<div class="pf-c-input-group">
<div class="pf-c-check">
<input class="pf-c-check__input"
type="checkbox"
id="hide-service-accounts"
name="hide-service-accounts"
?checked=${this.hideServiceAccounts}
@change=${() => {
this.hideServiceAccounts = !this.hideServiceAccounts;
this.page = 1;
this.fetch();
}} />
<label class="pf-c-check__label" for="hide-service-accounts">
${t`Hide service-accounts`}
</label>
</div>
</div>
</div>
</div>`;
}
}