Compare commits
7 Commits
version/0.
...
version/0.
| Author | SHA1 | Date | |
|---|---|---|---|
| c7f078ffcc | |||
| 571cb3d65f | |||
| 8c500c38b1 | |||
| 5644e57e6a | |||
| cfc181eed1 | |||
| 91bea38b8e | |||
| d95c5aa739 |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.9.0-pre6
|
current_version = 0.9.0-pre7
|
||||||
tag = True
|
tag = True
|
||||||
commit = True
|
commit = True
|
||||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
||||||
|
|||||||
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@ -16,11 +16,11 @@ jobs:
|
|||||||
- name: Building Docker Image
|
- name: Building Docker Image
|
||||||
run: docker build
|
run: docker build
|
||||||
--no-cache
|
--no-cache
|
||||||
-t beryju/passbook:0.9.0-pre6
|
-t beryju/passbook:0.9.0-pre7
|
||||||
-t beryju/passbook:latest
|
-t beryju/passbook:latest
|
||||||
-f Dockerfile .
|
-f Dockerfile .
|
||||||
- name: Push Docker Container to Registry (versioned)
|
- name: Push Docker Container to Registry (versioned)
|
||||||
run: docker push beryju/passbook:0.9.0-pre6
|
run: docker push beryju/passbook:0.9.0-pre7
|
||||||
- name: Push Docker Container to Registry (latest)
|
- name: Push Docker Container to Registry (latest)
|
||||||
run: docker push beryju/passbook:latest
|
run: docker push beryju/passbook:latest
|
||||||
build-gatekeeper:
|
build-gatekeeper:
|
||||||
@ -37,11 +37,11 @@ jobs:
|
|||||||
cd gatekeeper
|
cd gatekeeper
|
||||||
docker build \
|
docker build \
|
||||||
--no-cache \
|
--no-cache \
|
||||||
-t beryju/passbook-gatekeeper:0.9.0-pre6 \
|
-t beryju/passbook-gatekeeper:0.9.0-pre7 \
|
||||||
-t beryju/passbook-gatekeeper:latest \
|
-t beryju/passbook-gatekeeper:latest \
|
||||||
-f Dockerfile .
|
-f Dockerfile .
|
||||||
- name: Push Docker Container to Registry (versioned)
|
- name: Push Docker Container to Registry (versioned)
|
||||||
run: docker push beryju/passbook-gatekeeper:0.9.0-pre6
|
run: docker push beryju/passbook-gatekeeper:0.9.0-pre7
|
||||||
- name: Push Docker Container to Registry (latest)
|
- name: Push Docker Container to Registry (latest)
|
||||||
run: docker push beryju/passbook-gatekeeper:latest
|
run: docker push beryju/passbook-gatekeeper:latest
|
||||||
build-static:
|
build-static:
|
||||||
@ -66,11 +66,11 @@ jobs:
|
|||||||
run: docker build
|
run: docker build
|
||||||
--no-cache
|
--no-cache
|
||||||
--network=$(docker network ls | grep github | awk '{print $1}')
|
--network=$(docker network ls | grep github | awk '{print $1}')
|
||||||
-t beryju/passbook-static:0.9.0-pre6
|
-t beryju/passbook-static:0.9.0-pre7
|
||||||
-t beryju/passbook-static:latest
|
-t beryju/passbook-static:latest
|
||||||
-f static.Dockerfile .
|
-f static.Dockerfile .
|
||||||
- name: Push Docker Container to Registry (versioned)
|
- name: Push Docker Container to Registry (versioned)
|
||||||
run: docker push beryju/passbook-static:0.9.0-pre6
|
run: docker push beryju/passbook-static:0.9.0-pre7
|
||||||
- name: Push Docker Container to Registry (latest)
|
- name: Push Docker Container to Registry (latest)
|
||||||
run: docker push beryju/passbook-static:latest
|
run: docker push beryju/passbook-static:latest
|
||||||
test-release:
|
test-release:
|
||||||
@ -100,5 +100,5 @@ jobs:
|
|||||||
SENTRY_PROJECT: passbook
|
SENTRY_PROJECT: passbook
|
||||||
SENTRY_URL: https://sentry.beryju.org
|
SENTRY_URL: https://sentry.beryju.org
|
||||||
with:
|
with:
|
||||||
tagName: 0.9.0-pre6
|
tagName: 0.9.0-pre7
|
||||||
environment: production
|
environment: production
|
||||||
|
|||||||
@ -27,6 +27,7 @@ config:
|
|||||||
enabled: false
|
enabled: false
|
||||||
server_url: ""
|
server_url: ""
|
||||||
secret_token: ""
|
secret_token: ""
|
||||||
|
verify_server_cert: true
|
||||||
|
|
||||||
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
|
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
|
||||||
# This requires the CoreOS Prometheus Operator.
|
# This requires the CoreOS Prometheus Operator.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
appVersion: "0.9.0-pre6"
|
appVersion: "0.9.0-pre7"
|
||||||
description: A Helm chart for passbook.
|
description: A Helm chart for passbook.
|
||||||
name: passbook
|
name: passbook
|
||||||
version: "0.9.0-pre6"
|
version: "0.9.0-pre7"
|
||||||
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
|
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
|
||||||
|
|||||||
@ -25,3 +25,4 @@ data:
|
|||||||
enabled: {{ .Values.config.apm.enabled }}
|
enabled: {{ .Values.config.apm.enabled }}
|
||||||
server_url: "{{ .Values.config.apm.server_url }}"
|
server_url: "{{ .Values.config.apm.server_url }}"
|
||||||
secret_token: "{{ .Values.config.apm.server_token }}"
|
secret_token: "{{ .Values.config.apm.server_token }}"
|
||||||
|
verify_server_cert: {{ .Values.config.apm.verify_server_cert }}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
# This is a YAML-formatted file.
|
# This is a YAML-formatted file.
|
||||||
# Declare variables to be passed into your templates.
|
# Declare variables to be passed into your templates.
|
||||||
image:
|
image:
|
||||||
tag: 0.9.0-pre6
|
tag: 0.9.0-pre7
|
||||||
|
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ config:
|
|||||||
enabled: false
|
enabled: false
|
||||||
server_url: ""
|
server_url: ""
|
||||||
secret_token: ""
|
secret_token: ""
|
||||||
|
verify_server_cert: true
|
||||||
|
|
||||||
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
|
# This Helm chart ships with built-in Prometheus ServiceMonitors and Rules.
|
||||||
# This requires the CoreOS Prometheus Operator.
|
# This requires the CoreOS Prometheus Operator.
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook"""
|
"""passbook"""
|
||||||
__version__ = "0.9.0-pre6"
|
__version__ = "0.9.0-pre7"
|
||||||
|
|||||||
@ -4,6 +4,7 @@ from botocore.client import ClientError
|
|||||||
from django.core.exceptions import DisallowedHost, ValidationError
|
from django.core.exceptions import DisallowedHost, ValidationError
|
||||||
from django.db import InternalError, OperationalError, ProgrammingError
|
from django.db import InternalError, OperationalError, ProgrammingError
|
||||||
from django_redis.exceptions import ConnectionInterrupted
|
from django_redis.exceptions import ConnectionInterrupted
|
||||||
|
from elasticapm.transport.http import TransportException
|
||||||
from redis.exceptions import RedisError
|
from redis.exceptions import RedisError
|
||||||
from rest_framework.exceptions import APIException
|
from rest_framework.exceptions import APIException
|
||||||
from structlog import get_logger
|
from structlog import get_logger
|
||||||
@ -33,6 +34,7 @@ def before_send(event, hint):
|
|||||||
OSError,
|
OSError,
|
||||||
RedisError,
|
RedisError,
|
||||||
SentryIgnoredException,
|
SentryIgnoredException,
|
||||||
|
TransportException,
|
||||||
)
|
)
|
||||||
if "exc_info" in hint:
|
if "exc_info" in hint:
|
||||||
_, exc_value, _ = hint["exc_info"]
|
_, exc_value, _ = hint["exc_info"]
|
||||||
|
|||||||
@ -32,7 +32,8 @@ def update_score(request: HttpRequest, username: str, amount: int):
|
|||||||
# pylint: disable=unused-argument
|
# pylint: disable=unused-argument
|
||||||
def handle_failed_login(sender, request, credentials, **_):
|
def handle_failed_login(sender, request, credentials, **_):
|
||||||
"""Lower Score for failed loging attempts"""
|
"""Lower Score for failed loging attempts"""
|
||||||
update_score(request, credentials.get("username"), -1)
|
if "username" in credentials:
|
||||||
|
update_score(request, credentials.get("username"), -1)
|
||||||
|
|
||||||
|
|
||||||
@receiver(user_logged_in)
|
@receiver(user_logged_in)
|
||||||
|
|||||||
@ -281,7 +281,7 @@ if not DEBUG and _ERROR_REPORTING:
|
|||||||
release="passbook@%s" % __version__,
|
release="passbook@%s" % __version__,
|
||||||
)
|
)
|
||||||
|
|
||||||
_APM_ENABLED = CONFIG.y("apm.enabled", True)
|
_APM_ENABLED = CONFIG.y("apm.enabled", False)
|
||||||
if _APM_ENABLED:
|
if _APM_ENABLED:
|
||||||
INSTALLED_APPS.append("elasticapm.contrib.django")
|
INSTALLED_APPS.append("elasticapm.contrib.django")
|
||||||
ELASTIC_APM = {
|
ELASTIC_APM = {
|
||||||
@ -290,7 +290,8 @@ if _APM_ENABLED:
|
|||||||
"SERVICE_NAME": "passbook",
|
"SERVICE_NAME": "passbook",
|
||||||
"SERVICE_VERSION": __version__,
|
"SERVICE_VERSION": __version__,
|
||||||
"SECRET_TOKEN": CONFIG.y("apm.secret_token", ""),
|
"SECRET_TOKEN": CONFIG.y("apm.secret_token", ""),
|
||||||
"SERVER_URL": CONFIG.y("apm.secret_token", "http://localhost:8200"),
|
"SERVER_URL": CONFIG.y("apm.server_url", "http://localhost:8200"),
|
||||||
|
"VERIFY_SERVER_CERT": CONFIG.y_bool("apm.verify_server_cert", True),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +1,23 @@
|
|||||||
"""passbook oauth_client Authorization backend"""
|
"""passbook oauth_client Authorization backend"""
|
||||||
|
|
||||||
from django.contrib.auth.backends import ModelBackend
|
from django.contrib.auth.backends import ModelBackend
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.http import HttpRequest
|
||||||
|
|
||||||
|
from passbook.core.models import User
|
||||||
from passbook.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
|
from passbook.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
|
||||||
|
|
||||||
|
|
||||||
class AuthorizedServiceBackend(ModelBackend):
|
class AuthorizedServiceBackend(ModelBackend):
|
||||||
"Authentication backend for users registered with remote OAuth provider."
|
"Authentication backend for users registered with remote OAuth provider."
|
||||||
|
|
||||||
def authenticate(self, request, source=None, identifier=None):
|
def authenticate(
|
||||||
|
self, request: HttpRequest, source: OAuthSource, identifier: str
|
||||||
|
) -> User:
|
||||||
"Fetch user for a given source by id."
|
"Fetch user for a given source by id."
|
||||||
source_q = Q(source__name=source)
|
source_q = Q(source__name=source)
|
||||||
if isinstance(source, OAuthSource):
|
if isinstance(source, OAuthSource):
|
||||||
source_q = Q(source=source)
|
source_q = Q(source=source)
|
||||||
try:
|
access = UserOAuthSourceConnection.objects.filter(
|
||||||
access = UserOAuthSourceConnection.objects.filter(
|
source_q, identifier=identifier
|
||||||
source_q, identifier=identifier
|
).select_related("user")[0]
|
||||||
).select_related("user")[0]
|
return access.user
|
||||||
except IndexError:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return access.user
|
|
||||||
@ -89,16 +89,16 @@ class GitHubOAuthSource(OAuthSource):
|
|||||||
verbose_name_plural = _("GitHub OAuth Sources")
|
verbose_name_plural = _("GitHub OAuth Sources")
|
||||||
|
|
||||||
|
|
||||||
class TwitterOAuthSource(OAuthSource):
|
# class TwitterOAuthSource(OAuthSource):
|
||||||
"""Social Login using Twitter.com"""
|
# """Social Login using Twitter.com"""
|
||||||
|
|
||||||
form = "passbook.sources.oauth.forms.TwitterOAuthSourceForm"
|
# form = "passbook.sources.oauth.forms.TwitterOAuthSourceForm"
|
||||||
|
|
||||||
class Meta:
|
# class Meta:
|
||||||
|
|
||||||
abstract = True
|
# abstract = True
|
||||||
verbose_name = _("Twitter OAuth Source")
|
# verbose_name = _("Twitter OAuth Source")
|
||||||
verbose_name_plural = _("Twitter OAuth Sources")
|
# verbose_name_plural = _("Twitter OAuth Sources")
|
||||||
|
|
||||||
|
|
||||||
class FacebookOAuthSource(OAuthSource):
|
class FacebookOAuthSource(OAuthSource):
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
"""Oauth2 Client Settings"""
|
"""Oauth2 Client Settings"""
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = [
|
|
||||||
"passbook.sources.oauth.backends.AuthorizedServiceBackend",
|
|
||||||
]
|
|
||||||
|
|
||||||
PASSBOOK_SOURCES_OAUTH_TYPES = [
|
PASSBOOK_SOURCES_OAUTH_TYPES = [
|
||||||
"passbook.sources.oauth.types.discord",
|
"passbook.sources.oauth.types.discord",
|
||||||
"passbook.sources.oauth.types.facebook",
|
"passbook.sources.oauth.types.facebook",
|
||||||
|
|||||||
@ -50,9 +50,9 @@ class SourceTypeManager:
|
|||||||
return self.__source_types[kind.value][source.provider_type]
|
return self.__source_types[kind.value][source.provider_type]
|
||||||
LOGGER.warning("no matching type found, using default")
|
LOGGER.warning("no matching type found, using default")
|
||||||
# Return defaults
|
# Return defaults
|
||||||
if kind.value == RequestKind.callback:
|
if kind == RequestKind.callback:
|
||||||
return OAuthCallback
|
return OAuthCallback
|
||||||
if kind.value == RequestKind.redirect:
|
if kind == RequestKind.redirect:
|
||||||
return OAuthRedirect
|
return OAuthRedirect
|
||||||
raise KeyError(
|
raise KeyError(
|
||||||
f"Provider Type {source.provider_type} (type {kind.value}) not found."
|
f"Provider Type {source.provider_type} (type {kind.value}) not found."
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
"""Twitter OAuth Views"""
|
"""Twitter OAuth Views"""
|
||||||
from passbook.sources.oauth.types.manager import MANAGER, RequestKind
|
# from passbook.sources.oauth.types.manager import MANAGER, RequestKind
|
||||||
from passbook.sources.oauth.utils import user_get_or_create
|
from passbook.sources.oauth.utils import user_get_or_create
|
||||||
from passbook.sources.oauth.views.core import OAuthCallback
|
from passbook.sources.oauth.views.core import OAuthCallback
|
||||||
|
|
||||||
|
|
||||||
@MANAGER.source(kind=RequestKind.callback, name="Twitter")
|
# @MANAGER.source(kind=RequestKind.callback, name="Twitter")
|
||||||
class TwitterOAuthCallback(OAuthCallback):
|
class TwitterOAuthCallback(OAuthCallback):
|
||||||
"""Twitter OAuth2 Callback"""
|
"""Twitter OAuth2 Callback"""
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ from typing import Any, Callable, Dict, Optional
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import authenticate
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import Http404, HttpRequest, HttpResponse
|
from django.http import Http404, HttpRequest, HttpResponse
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
@ -22,6 +21,7 @@ from passbook.flows.planner import (
|
|||||||
)
|
)
|
||||||
from passbook.flows.views import SESSION_KEY_PLAN
|
from passbook.flows.views import SESSION_KEY_PLAN
|
||||||
from passbook.lib.utils.urls import redirect_with_qs
|
from passbook.lib.utils.urls import redirect_with_qs
|
||||||
|
from passbook.sources.oauth.auth import AuthorizedServiceBackend
|
||||||
from passbook.sources.oauth.clients import BaseOAuthClient, get_client
|
from passbook.sources.oauth.clients import BaseOAuthClient, get_client
|
||||||
from passbook.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
|
from passbook.sources.oauth.models import OAuthSource, UserOAuthSourceConnection
|
||||||
from passbook.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
from passbook.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||||
@ -134,7 +134,7 @@ class OAuthCallback(OAuthClientMixin, View):
|
|||||||
identifier=identifier,
|
identifier=identifier,
|
||||||
access_token=token.get("access_token"),
|
access_token=token.get("access_token"),
|
||||||
)
|
)
|
||||||
user = authenticate(
|
user = AuthorizedServiceBackend().authenticate(
|
||||||
source=self.source, identifier=identifier, request=request
|
source=self.source, identifier=identifier, request=request
|
||||||
)
|
)
|
||||||
if user is None:
|
if user is None:
|
||||||
@ -181,7 +181,8 @@ class OAuthCallback(OAuthClientMixin, View):
|
|||||||
self.request,
|
self.request,
|
||||||
{
|
{
|
||||||
PLAN_CONTEXT_PENDING_USER: user,
|
PLAN_CONTEXT_PENDING_USER: user,
|
||||||
PLAN_CONTEXT_AUTHENTICATION_BACKEND: user.backend,
|
# Since we authenticate the user by their token, they have no backend set
|
||||||
|
PLAN_CONTEXT_AUTHENTICATION_BACKEND: "django.contrib.auth.backends.ModelBackend",
|
||||||
PLAN_CONTEXT_SSO: True,
|
PLAN_CONTEXT_SSO: True,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -206,7 +207,7 @@ class OAuthCallback(OAuthClientMixin, View):
|
|||||||
% {"source": self.source.name}
|
% {"source": self.source.name}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
user = authenticate(
|
user = AuthorizedServiceBackend().authenticate(
|
||||||
source=access.source, identifier=access.identifier, request=self.request
|
source=access.source, identifier=access.identifier, request=self.request
|
||||||
)
|
)
|
||||||
return self.handle_login_flow(source.authentication_flow, user)
|
return self.handle_login_flow(source.authentication_flow, user)
|
||||||
@ -249,7 +250,7 @@ class OAuthCallback(OAuthClientMixin, View):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
# User was not authenticated, new user has been created
|
# User was not authenticated, new user has been created
|
||||||
user = authenticate(
|
user = AuthorizedServiceBackend().authenticate(
|
||||||
source=access.source, identifier=access.identifier, request=self.request
|
source=access.source, identifier=access.identifier, request=self.request
|
||||||
)
|
)
|
||||||
messages.success(
|
messages.success(
|
||||||
|
|||||||
Reference in New Issue
Block a user