Compare commits

...

12 Commits

28 changed files with 87 additions and 26 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.1.5-beta
current_version = 0.1.8-beta
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)

View File

@ -53,7 +53,7 @@ package-docker:
before_script:
- echo "{\"auths\":{\"docker.$NEXUS_URL\":{\"auth\":\"$NEXUS_AUTH\"}}}" > /kaniko/.docker/config.json
script:
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.pkg.beryju.org/passbook:latest --destination docker.pkg.beryju.org/passbook:0.1.5-beta
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.pkg.beryju.org/passbook:latest --destination docker.pkg.beryju.org/passbook:0.1.8-beta
stage: build
only:
- tags
@ -78,6 +78,7 @@ package-debian:
- virtualenv env
- source env/bin/activate
- pip3 install -U -r requirements.txt -r requirements-dev.txt
- ./manage.py collectstatic --no-input
image: ubuntu:18.04
script:
- debuild -us -uc

20
debian/changelog vendored
View File

@ -1,3 +1,23 @@
passbook (0.1.7) stable; urgency=medium
* bump version: 0.1.3-beta -> 0.1.4-beta
* implicitly add kubernetes-healthcheck-host in helm configmap
* fix debian build (again)
* add PropertyMapping Model, add Subclass for SAML, test with AWS
* add custom DynamicArrayField to better handle arrays
* format data before inserting it
* bump version: 0.1.4-beta -> 0.1.5-beta
* fix static files missing for debian package
* fix password not getting set on user import
* remove audit's login attempt
* add passing property to PolicyEngine
* fix captcha factor not loading keys from Factor class
* bump version: 0.1.5-beta -> 0.1.6-beta
* fix MATCH_EXACT not working as intended
* Improve access control for saml
-- Jens Langhammer <jens.langhammer@beryju.org> Fri, 08 Mar 2019 20:37:05 +0000
passbook (0.1.4) stable; urgency=medium
* initial debian package release

View File

@ -1,6 +1,6 @@
apiVersion: v1
appVersion: "0.1.5-beta"
appVersion: "0.1.8-beta"
description: A Helm chart for passbook.
name: passbook
version: "0.1.5-beta"
version: "0.1.8-beta"
icon: https://passbook.beryju.org/images/logo.png

View File

@ -5,7 +5,7 @@
replicaCount: 1
image:
tag: 0.1.5-beta
tag: 0.1.8-beta
nameOverride: ""

View File

@ -1,2 +1,2 @@
"""passbook"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook admin"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook api"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook audit Header"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -0,0 +1,16 @@
# Generated by Django 2.1.7 on 2019-03-08 14:53
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('passbook_audit', '0003_auto_20190221_1240'),
]
operations = [
migrations.DeleteModel(
name='LoginAttempt',
),
]

View File

@ -1,2 +1,2 @@
"""passbook captcha_factor Header"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -13,3 +13,10 @@ class CaptchaFactor(FormView, AuthenticationFactor):
def form_valid(self, form):
return self.authenticator.user_ok()
def get_form(self, form_class=None):
form = CaptchaForm(**self.get_form_kwargs())
form.fields['captcha'].public_key = '6Lfi1w8TAAAAAELH-YiWp0OFItmMzvjGmw2xkvUN'
form.fields['captcha'].private_key = '6Lfi1w8TAAAAAMQI3f86tGMvd1QkcqqVQyBWI23D'
form.fields['captcha'].widget.attrs["data-sitekey"] = form.fields['captcha'].public_key
return form

View File

@ -1,2 +1,2 @@
"""passbook core"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -66,7 +66,7 @@ class AuthenticationView(UserPassesTestMixin, View):
for factor in _all_factors:
policy_engine = PolicyEngine(factor.policies.all())
policy_engine.for_user(self.pending_user).with_request(request).build()
if policy_engine.result[0]:
if policy_engine.passing:
self.pending_factors.append((factor.uuid.hex, factor.type))
# Read and instantiate factor from session
factor_uuid, factor_class = None, None

View File

@ -37,7 +37,8 @@ class Command(BaseCommand):
User.objects.create(
username=user.get('username'),
email=user.get('email'),
name=user.get('name'))
name=user.get('name'),
password=user.get('password'))
LOGGER.debug('Created User %s', user.get('username'))
except ValidationError as exc:
LOGGER.warning('User %s caused %r, skipping', user.get('username'), exc)

View File

@ -288,6 +288,8 @@ class FieldMatcherPolicy(Policy):
if self.match_action == FieldMatcherPolicy.MATCH_REGEXP:
pattern = re.compile(self.value)
passes = bool(pattern.match(user_field_value))
if self.match_action == FieldMatcherPolicy.MATCH_EXACT:
passes = user_field_value == self.value
LOGGER.debug("User got '%r'", passes)
return passes

View File

@ -79,3 +79,8 @@ class PolicyEngine:
if not passing:
return False, messages
return True, messages
@property
def passing(self):
"""Only get true/false if user passes"""
return self.result[0]

View File

@ -17,6 +17,6 @@ def user_factors(context):
_link = factor.has_user_settings()
policy_engine = PolicyEngine(factor.policies.all())
policy_engine.for_user(user).with_request(context.get('request')).build()
if policy_engine.result[0] and _link:
if policy_engine.passing and _link:
matching_factors.append(_link)
return matching_factors

View File

@ -1,2 +1,2 @@
"""passbook hibp_policy"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""Passbook ldap app Header"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook lib"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook oauth_client Header"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook oauth_provider Header"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook otp Header"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook password_expiry"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -1,2 +1,2 @@
"""passbook saml_idp Header"""
__version__ = '0.1.5-beta'
__version__ = '0.1.8-beta'

View File

@ -18,7 +18,7 @@
<input type="hidden" name="SAMLResponse" value="{{ saml_response }}" />
<div class="login-group">
<h3>
{% blocktrans with remote=remote.name %}
{% blocktrans with remote=remote.application.name %}
You're about to sign into {{ remote }}
{% endblocktrans %}
</h3>

View File

@ -9,6 +9,7 @@ from django.http import HttpResponse, HttpResponseBadRequest
from django.shortcuts import get_object_or_404, redirect, render, reverse
from django.utils.datastructures import MultiValueDictKeyError
from django.utils.decorators import method_decorator
from django.utils.translation import gettext as _
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from signxml.util import strip_pem_header
@ -105,13 +106,17 @@ class LoginProcessView(ProviderMixin, LoginRequiredMixin, View):
"""Check if user has access to application"""
policy_engine = PolicyEngine(self.provider.application.policies.all())
policy_engine.for_user(self.request.user).with_request(self.request).build()
return policy_engine.result
return policy_engine.passing
def get(self, request, application):
"""Handle get request, i.e. render form"""
LOGGER.debug("Request: %s", request)
if not self._has_access():
return render(request, 'login/denied.html', {
'title': _("You don't have access to this application")
})
# Check if user has access
if self.provider.application.skip_authorization and self._has_access():
if self.provider.application.skip_authorization:
ctx = self.provider.processor.generate_response()
# Log Application Authorization
AuditEntry.create(
@ -133,8 +138,12 @@ class LoginProcessView(ProviderMixin, LoginRequiredMixin, View):
def post(self, request, application):
"""Handle post request, return back to ACS"""
LOGGER.debug("Request: %s", request)
if not self._has_access():
return render(request, 'login/denied.html', {
'title': _("You don't have access to this application")
})
# Check if user has access
if request.POST.get('ACSUrl', None) and self._has_access():
if request.POST.get('ACSUrl', None):
# User accepted request
AuditEntry.create(
action=AuditEntry.ACTION_AUTHORIZE_APPLICATION,