Compare commits
14 Commits
version/0.
...
version/0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e9154a0ea | |||
| e0ef061771 | |||
| b8694a7ade | |||
| 10d6a30f2c | |||
| 8c94aef6d0 | |||
| 19bd3bfffb | |||
| 8611ac624c | |||
| fa93b59a8c | |||
| 8b66b40f0d | |||
| c2756f15fc | |||
| 408e205c5f | |||
| 5f3ab49535 | |||
| 33431ae013 | |||
| b40ac6dc5d |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.0.7-alpha
|
current_version = 0.0.8-alpha
|
||||||
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>.*)
|
||||||
|
|||||||
@ -54,7 +54,7 @@ package-docker:
|
|||||||
before_script:
|
before_script:
|
||||||
- echo "{\"auths\":{\"https://docker.$NEXUS_URL/\":{\"username\":\"$NEXUS_USER\",\"password\":\"$NEXUS_PASS\"}}}" > /kaniko/.docker/config.json
|
- echo "{\"auths\":{\"https://docker.$NEXUS_URL/\":{\"username\":\"$NEXUS_USER\",\"password\":\"$NEXUS_PASS\"}}}" > /kaniko/.docker/config.json
|
||||||
script:
|
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.0.7-alpha
|
- /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.0.8-alpha
|
||||||
stage: build
|
stage: build
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
"""passbook provider"""
|
"""passbook provider"""
|
||||||
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
|
from allauth.socialaccount.providers.oauth2.urls import default_urlpatterns
|
||||||
|
|
||||||
from allauth_passbook.provider import PassbookProvider
|
from allauth_passbook.provider import PassbookProvider
|
||||||
|
|
||||||
urlpatterns = default_urlpatterns(PassbookProvider)
|
urlpatterns = default_urlpatterns(PassbookProvider)
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
"""passbook adapter"""
|
"""passbook adapter"""
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from allauth.socialaccount import app_settings
|
from allauth.socialaccount import app_settings
|
||||||
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
|
from allauth.socialaccount.providers.oauth2.views import (OAuth2Adapter,
|
||||||
OAuth2CallbackView,
|
OAuth2CallbackView,
|
||||||
OAuth2LoginView)
|
OAuth2LoginView)
|
||||||
|
|
||||||
from allauth_passbook.provider import PassbookProvider
|
from allauth_passbook.provider import PassbookProvider
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
appVersion: "0.0.7-alpha"
|
appVersion: "0.0.8-alpha"
|
||||||
description: A Helm chart for passbook.
|
description: A Helm chart for passbook.
|
||||||
name: passbook
|
name: passbook
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook"""
|
"""passbook"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook admin"""
|
"""passbook admin"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Applications" %}</h1>
|
<h1><span class="pficon-applications"></span> {% trans "Applications" %}</h1>
|
||||||
<span>{% trans "External Applications which use passbook as Identity-Provider, utilizing protocols like OAuth2 and SAML." %}</span>
|
<span>{% trans "External Applications which use passbook as Identity-Provider, utilizing protocols like OAuth2 and SAML." %}</span>
|
||||||
<hr>
|
<hr>
|
||||||
<a href="{% url 'passbook_admin:application-create' %}" class="btn btn-primary">
|
<a href="{% url 'passbook_admin:application-create' %}" class="btn btn-primary">
|
||||||
@ -30,8 +30,10 @@
|
|||||||
<td>{{ application.name }}</td>
|
<td>{{ application.name }}</td>
|
||||||
<td>{{ application.provider }}</td>
|
<td>{{ application.provider }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:application-update' pk=application.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
<a class="btn btn-default btn-sm"
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:application-delete' pk=application.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
href="{% url 'passbook_admin:application-update' pk=application.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
<a class="btn btn-default btn-sm"
|
||||||
|
href="{% url 'passbook_admin:application-delete' pk=application.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Audit Log" %}</h1>
|
<h1><span class="pficon-catalog"></span> {% trans "Audit Log" %}</h1>
|
||||||
<div id="pf-list-standard" class="list-group list-view-pf list-view-pf-view">
|
<div id="pf-list-standard" class="list-group list-view-pf list-view-pf-view">
|
||||||
{% for entry in object_list %}
|
{% for entry in object_list %}
|
||||||
<div class="list-group-item">
|
<div class="list-group-item">
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Factors" %}</h1>
|
<h1><span class="pficon-plugged"></span> {% trans "Factors" %}</h1>
|
||||||
<span>{% trans "Factors required for a user to successfully authenticate." %}</span>
|
<span>{% trans "Factors required for a user to successfully authenticate." %}</span>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
@ -20,7 +20,8 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" role="menu" aria-labelledby="createDropdown">
|
<ul class="dropdown-menu" role="menu" aria-labelledby="createDropdown">
|
||||||
{% for type, name in types.items %}
|
{% for type, name in types.items %}
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="{% url 'passbook_admin:factor-create' %}?type={{ type }}">{{ name }}</a></li>
|
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||||
|
href="{% url 'passbook_admin:factor-create' %}?type={{ type }}">{{ name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Invitations" %}</h1>
|
<h1><span class="pficon-migration"></span> {% trans "Invitations" %}</h1>
|
||||||
<span>{% trans "Create Invitation Links which optionally force a username or expire on a set date." %}</span>
|
<span>{% trans "Create Invitation Links which optionally force a username or expire on a set date." %}</span>
|
||||||
<hr>
|
<hr>
|
||||||
<a href="{% url 'passbook_admin:invitation-create' %}" class="btn btn-primary">
|
<a href="{% url 'passbook_admin:invitation-create' %}" class="btn btn-primary">
|
||||||
@ -28,9 +28,12 @@
|
|||||||
{% for invitation in object_list %}
|
{% for invitation in object_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ invitation.expires|default:"Never" }}</td>
|
<td>{{ invitation.expires|default:"Never" }}</td>
|
||||||
<td><pre>{{ invitation.link }}</pre></td>
|
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:invitation-delete' pk=invitation.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
<pre>{{ invitation.link }}</pre>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a class="btn btn-default btn-sm"
|
||||||
|
href="{% url 'passbook_admin:invitation-delete' pk=invitation.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -7,11 +7,18 @@
|
|||||||
<div class="col-xs-6 col-sm-2 col-md-2">
|
<div class="col-xs-6 col-sm-2 col-md-2">
|
||||||
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
||||||
<h2 class="card-pf-title">
|
<h2 class="card-pf-title">
|
||||||
<a href="#"><span class="fa fa-shield"></span><span class="card-pf-aggregate-status-count"></span> {% trans 'Applications' %}</a>
|
<a href="{% url 'passbook_admin:applications' %}">
|
||||||
|
<span class="pficon-applications"></span>
|
||||||
|
<span class="card-pf-aggregate-status-count"></span> {% trans 'Applications' %}
|
||||||
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="card-pf-body">
|
<div class="card-pf-body">
|
||||||
<p class="card-pf-aggregate-status-notifications">
|
<p class="card-pf-aggregate-status-notifications">
|
||||||
<span class="card-pf-aggregate-status-notification"><a href="#"><span class="pficon pficon-ok"></span>{{ application_count }}</a></span>
|
<span class="card-pf-aggregate-status-notification">
|
||||||
|
<a href="{% url 'passbook_admin:applications' %}">
|
||||||
|
<span class="pficon pficon-ok"></span>{{ application_count }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -19,11 +26,18 @@
|
|||||||
<div class="col-xs-6 col-sm-2 col-md-2">
|
<div class="col-xs-6 col-sm-2 col-md-2">
|
||||||
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
||||||
<h2 class="card-pf-title">
|
<h2 class="card-pf-title">
|
||||||
<a href="#"><span class="fa fa-shield"></span><span class="card-pf-aggregate-status-count"></span> {% trans 'Sources' %}</a>
|
<a href="{% url 'passbook_admin:sources' %}">
|
||||||
|
<span class="pficon-resource-pool"></span>
|
||||||
|
<span class="card-pf-aggregate-status-count"></span> {% trans 'Sources' %}
|
||||||
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="card-pf-body">
|
<div class="card-pf-body">
|
||||||
<p class="card-pf-aggregate-status-notifications">
|
<p class="card-pf-aggregate-status-notifications">
|
||||||
<span class="card-pf-aggregate-status-notification"><a href="#"><span class="pficon pficon-ok"></span>{{ source_count }}</a></span>
|
<span class="card-pf-aggregate-status-notification">
|
||||||
|
<a href="{% url 'passbook_admin:sources' %}">
|
||||||
|
<span class="pficon pficon-ok"></span>{{ source_count }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -31,11 +45,18 @@
|
|||||||
<div class="col-xs-6 col-sm-2 col-md-2">
|
<div class="col-xs-6 col-sm-2 col-md-2">
|
||||||
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
||||||
<h2 class="card-pf-title">
|
<h2 class="card-pf-title">
|
||||||
<a href="#"><span class="fa fa-shield"></span><span class="card-pf-aggregate-status-count"></span> {% trans 'Providers' %}</a>
|
<a href="{% url 'passbook_admin:providers' %}">
|
||||||
|
<span class="pficon-integration"></span>
|
||||||
|
<span class="card-pf-aggregate-status-count"></span> {% trans 'Providers' %}
|
||||||
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="card-pf-body">
|
<div class="card-pf-body">
|
||||||
<p class="card-pf-aggregate-status-notifications">
|
<p class="card-pf-aggregate-status-notifications">
|
||||||
<span class="card-pf-aggregate-status-notification"><a href="#"><span class="pficon pficon-ok"></span>{{ provider_count }}</a></span>
|
<span class="card-pf-aggregate-status-notification">
|
||||||
|
<a href="{% url 'passbook_admin:providers' %}">
|
||||||
|
<span class="pficon pficon-ok"></span>{{ provider_count }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,11 +64,18 @@
|
|||||||
<div class="col-xs-6 col-sm-2 col-md-2">
|
<div class="col-xs-6 col-sm-2 col-md-2">
|
||||||
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
||||||
<h2 class="card-pf-title">
|
<h2 class="card-pf-title">
|
||||||
<a href="#"><span class="fa fa-shield"></span><span class="card-pf-aggregate-status-count"></span> {% trans 'Factors' %}</a>
|
<a href="{% url 'passbook_admin:factors' %}">
|
||||||
|
<span class="pficon-plugged"></span>
|
||||||
|
<span class="card-pf-aggregate-status-count"></span> {% trans 'Factors' %}
|
||||||
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="card-pf-body">
|
<div class="card-pf-body">
|
||||||
<p class="card-pf-aggregate-status-notifications">
|
<p class="card-pf-aggregate-status-notifications">
|
||||||
<span class="card-pf-aggregate-status-notification"><a href="#"><span class="pficon pficon-ok"></span>{{ factor_count }}</a></span>
|
<span class="card-pf-aggregate-status-notification">
|
||||||
|
<a href="{% url 'passbook_admin:factors' %}">
|
||||||
|
<span class="pficon pficon-ok"></span>{{ factor_count }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -55,11 +83,18 @@
|
|||||||
<div class="col-xs-6 col-sm-2 col-md-2">
|
<div class="col-xs-6 col-sm-2 col-md-2">
|
||||||
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
||||||
<h2 class="card-pf-title">
|
<h2 class="card-pf-title">
|
||||||
<a href="#"><span class="fa fa-shield"></span><span class="card-pf-aggregate-status-count"></span> {% trans 'Invitation' %}</a>
|
<a href="{% url 'passbook_admin:policies' %}">
|
||||||
|
<span class="pficon-infrastructure"></span>
|
||||||
|
<span class="card-pf-aggregate-status-count"></span> {% trans 'Policies' %}
|
||||||
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="card-pf-body">
|
<div class="card-pf-body">
|
||||||
<p class="card-pf-aggregate-status-notifications">
|
<p class="card-pf-aggregate-status-notifications">
|
||||||
<span class="card-pf-aggregate-status-notification"><a href="#"><span class="pficon pficon-ok"></span>{{ invitation_count }}</a></span>
|
<span class="card-pf-aggregate-status-notification">
|
||||||
|
<a href="{% url 'passbook_admin:policies' %}">
|
||||||
|
<span class="pficon pficon-ok"></span>{{ policy_count }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -67,11 +102,18 @@
|
|||||||
<div class="col-xs-6 col-sm-2 col-md-2">
|
<div class="col-xs-6 col-sm-2 col-md-2">
|
||||||
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
||||||
<h2 class="card-pf-title">
|
<h2 class="card-pf-title">
|
||||||
<a href="#"><span class="fa fa-shield"></span><span class="card-pf-aggregate-status-count"></span> {% trans 'Policies' %}</a>
|
<a href="{% url 'passbook_admin:invitations' %}">
|
||||||
|
<span class="pficon-migration"></span>
|
||||||
|
<span class="card-pf-aggregate-status-count"></span> {% trans 'Invitation' %}
|
||||||
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="card-pf-body">
|
<div class="card-pf-body">
|
||||||
<p class="card-pf-aggregate-status-notifications">
|
<p class="card-pf-aggregate-status-notifications">
|
||||||
<span class="card-pf-aggregate-status-notification"><a href="#"><span class="pficon pficon-ok"></span>{{ policy_count }}</a></span>
|
<span class="card-pf-aggregate-status-notification">
|
||||||
|
<a href="{% url 'passbook_admin:invitations' %}">
|
||||||
|
<span class="pficon pficon-ok"></span>{{ invitation_count }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -79,11 +121,18 @@
|
|||||||
<div class="col-xs-6 col-sm-2 col-md-2">
|
<div class="col-xs-6 col-sm-2 col-md-2">
|
||||||
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
<div class="card-pf card-pf-accented card-pf-aggregate-status">
|
||||||
<h2 class="card-pf-title">
|
<h2 class="card-pf-title">
|
||||||
<a href="#"><span class="fa fa-shield"></span><span class="card-pf-aggregate-status-count"></span> {% trans 'Users' %}</a>
|
<a href="{% url 'passbook_admin:users' %}">
|
||||||
|
<span class="pficon-users"></span>
|
||||||
|
<span class="card-pf-aggregate-status-count"></span> {% trans 'Users' %}
|
||||||
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
<div class="card-pf-body">
|
<div class="card-pf-body">
|
||||||
<p class="card-pf-aggregate-status-notifications">
|
<p class="card-pf-aggregate-status-notifications">
|
||||||
<span class="card-pf-aggregate-status-notification"><a href="#"><span class="pficon pficon-ok"></span>{{ user_count }}</a></span>
|
<span class="card-pf-aggregate-status-notification">
|
||||||
|
<a href="{% url 'passbook_admin:users' %}">
|
||||||
|
<span class="pficon pficon-ok"></span>{{ user_count }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Policies" %}</h1>
|
<h1><span class="pficon-infrastructure"></span> {% trans "Policies" %}</h1>
|
||||||
<span>{% trans "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Factors." %}</span>
|
<span>{% trans "Allow users to use Applications based on properties, enforce Password Criteria and selectively apply Factors." %}</span>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
@ -19,7 +19,8 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" role="menu" aria-labelledby="createDropdown">
|
<ul class="dropdown-menu" role="menu" aria-labelledby="createDropdown">
|
||||||
{% for type, name in types.items %}
|
{% for type, name in types.items %}
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="{% url 'passbook_admin:policy-create' %}?type={{ type }}">{{ name }}</a></li>
|
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||||
|
href="{% url 'passbook_admin:policy-create' %}?type={{ type }}">{{ name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -38,9 +39,12 @@
|
|||||||
<td>{{ policy.name }}</td>
|
<td>{{ policy.name }}</td>
|
||||||
<td>{{ policy|fieldtype }}</td>
|
<td>{{ policy|fieldtype }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:policy-update' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
<a class="btn btn-default btn-sm"
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:policy-test' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Test' %}</a>
|
href="{% url 'passbook_admin:policy-update' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:policy-delete' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
<a class="btn btn-default btn-sm"
|
||||||
|
href="{% url 'passbook_admin:policy-test' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Test' %}</a>
|
||||||
|
<a class="btn btn-default btn-sm"
|
||||||
|
href="{% url 'passbook_admin:policy-delete' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Providers" %}</h1>
|
<h1><span class="pficon-integration"></span> {% trans "Providers" %}</h1>
|
||||||
<span>{% trans "Authentication Protocol Provider, used as Protocol behind an Application." %}</span>
|
<span>{% trans "Authentication Protocol Provider, used as Protocol behind an Application." %}</span>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
@ -20,7 +20,8 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" role="menu" aria-labelledby="createDropdown">
|
<ul class="dropdown-menu" role="menu" aria-labelledby="createDropdown">
|
||||||
{% for type, name in types.items %}
|
{% for type, name in types.items %}
|
||||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="{% url 'passbook_admin:provider-create' %}?type={{ type }}">{{ name }}</a></li>
|
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||||
|
href="{% url 'passbook_admin:provider-create' %}?type={{ type }}">{{ name }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -39,11 +40,14 @@
|
|||||||
<td>{{ provider.name }}</td>
|
<td>{{ provider.name }}</td>
|
||||||
<td>{{ provider|fieldtype }}</td>
|
<td>{{ provider|fieldtype }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:provider-update' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
<a class="btn btn-default btn-sm"
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:provider-delete' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
href="{% url 'passbook_admin:provider-update' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
<a class="btn btn-default btn-sm"
|
||||||
|
href="{% url 'passbook_admin:provider-delete' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
{% get_links provider as links %}
|
{% get_links provider as links %}
|
||||||
{% for name, href in links.items %}
|
{% for name, href in links.items %}
|
||||||
<a class="btn btn-default btn-sm" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
<a class="btn btn-default btn-sm"
|
||||||
|
href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Sources" %}</h1>
|
<h1><span class="pficon-resource-pool"></span> {% trans "Sources" %}</h1>
|
||||||
<span>{% trans "External Sources which can be used to get Identities into passbook, for example Social Providers like Twiter and GitHub or Enterprise Providers like ADFS and LDAP." %}</span>
|
<span>{% trans "External Sources which can be used to get Identities into passbook, for example Social Providers like Twiter and GitHub or Enterprise Providers like ADFS and LDAP." %}</span>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
@ -27,6 +27,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{% trans 'Name' %}</th>
|
<th>{% trans 'Name' %}</th>
|
||||||
<th>{% trans 'Class' %}</th>
|
<th>{% trans 'Class' %}</th>
|
||||||
|
<th>{% trans 'Additional Info' %}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -35,6 +36,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ source.name }}</td>
|
<td>{{ source.name }}</td>
|
||||||
<td>{{ source|fieldtype }}</td>
|
<td>{{ source|fieldtype }}</td>
|
||||||
|
<td>{{ source.additional_info }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-sm"
|
<a class="btn btn-default btn-sm"
|
||||||
href="{% url 'passbook_admin:source-update' pk=source.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
href="{% url 'passbook_admin:source-update' pk=source.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>{% trans "Users" %}</h1>
|
<h1><span class="pficon-users"></span> {% trans "Users" %}</h1>
|
||||||
<hr>
|
<hr>
|
||||||
<table class="table table-striped table-bordered">
|
<table class="table table-striped table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
@ -27,8 +27,10 @@
|
|||||||
<td>{{ user.is_active }}</td>
|
<td>{{ user.is_active }}</td>
|
||||||
<td>{{ user.last_login }}</td>
|
<td>{{ user.last_login }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:user-update' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
<a class="btn btn-default btn-sm"
|
||||||
<a class="btn btn-default btn-sm" href="{% url 'passbook_admin:user-delete' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
href="{% url 'passbook_admin:user-update' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a>
|
||||||
|
<a class="btn btn-default btn-sm"
|
||||||
|
href="{% url 'passbook_admin:user-delete' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -5,3 +5,7 @@
|
|||||||
{% block above_form %}
|
{% block above_form %}
|
||||||
<h1>{% trans 'Create' %}</h1>
|
<h1>{% trans 'Create' %}</h1>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block action %}
|
||||||
|
{% trans 'Create' %}
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<form action="" method="post" class="form-horizontal">
|
<form action="" method="post" class="form-horizontal">
|
||||||
{% include 'partials/form.html' with form=form %}
|
{% include 'partials/form.html' with form=form %}
|
||||||
<a class="btn btn-default" href="{% back %}">{% trans "Cancel" %}</a>
|
<a class="btn btn-default" href="{% back %}">{% trans "Cancel" %}</a>
|
||||||
<input type="submit" class="btn btn-primary" value="{% trans 'Create' %}" />
|
<input type="submit" class="btn btn-primary" value="{% block action %}{% endblock %}" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,3 +5,7 @@
|
|||||||
{% block above_form %}
|
{% block above_form %}
|
||||||
<h1>{% trans 'Update' %}</h1>
|
<h1>{% trans 'Update' %}</h1>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block action %}
|
||||||
|
{% trans 'Update' %}
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@ -39,19 +39,18 @@ class FactorCreateView(SuccessMessageMixin, AdminRequiredMixin, CreateView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
kwargs = super().get_context_data(**kwargs)
|
kwargs = super().get_context_data(**kwargs)
|
||||||
source_type = self.request.GET.get('type')
|
factor_type = self.request.GET.get('type')
|
||||||
model = next(x for x in all_subclasses(Factor) if x.__name__ == source_type)
|
model = next(x for x in all_subclasses(Factor) if x.__name__ == factor_type)
|
||||||
kwargs['type'] = model._meta.verbose_name
|
kwargs['type'] = model._meta.verbose_name
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
source_type = self.request.GET.get('type')
|
factor_type = self.request.GET.get('type')
|
||||||
model = next(x for x in all_subclasses(Factor) if x.__name__ == source_type)
|
model = next(x for x in all_subclasses(Factor) if x.__name__ == factor_type)
|
||||||
if not model:
|
if not model:
|
||||||
raise Http404
|
raise Http404
|
||||||
return path_to_class(model.form)
|
return path_to_class(model.form)
|
||||||
|
|
||||||
|
|
||||||
class FactorUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView):
|
class FactorUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView):
|
||||||
"""Update factor"""
|
"""Update factor"""
|
||||||
|
|
||||||
@ -61,11 +60,12 @@ class FactorUpdateView(SuccessMessageMixin, AdminRequiredMixin, UpdateView):
|
|||||||
success_message = _('Successfully updated Factor')
|
success_message = _('Successfully updated Factor')
|
||||||
|
|
||||||
def get_form_class(self):
|
def get_form_class(self):
|
||||||
source_type = self.request.GET.get('type')
|
form_class_path = self.get_object().form
|
||||||
model = next(x for x in all_subclasses(Factor) if x.__name__ == source_type)
|
form_class = path_to_class(form_class_path)
|
||||||
if not model:
|
return form_class
|
||||||
raise Http404
|
|
||||||
return path_to_class(model.form)
|
def get_object(self, queryset=None):
|
||||||
|
return Factor.objects.filter(pk=self.kwargs.get('pk')).select_subclasses().first()
|
||||||
|
|
||||||
class FactorDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView):
|
class FactorDeleteView(SuccessMessageMixin, AdminRequiredMixin, DeleteView):
|
||||||
"""Delete factor"""
|
"""Delete factor"""
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook api"""
|
"""passbook api"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook audit Header"""
|
"""passbook audit Header"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -84,6 +84,8 @@ class LoginAttempt(CreatedUpdatedModel):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def attempt(target_uid, request):
|
def attempt(target_uid, request):
|
||||||
"""Helper function to create attempt or count up existing one"""
|
"""Helper function to create attempt or count up existing one"""
|
||||||
|
if not target_uid:
|
||||||
|
return
|
||||||
client_ip, _ = get_client_ip(request)
|
client_ip, _ = get_client_ip(request)
|
||||||
# Since we can only use 254 chars for target_uid, truncate target_uid.
|
# Since we can only use 254 chars for target_uid, truncate target_uid.
|
||||||
target_uid = target_uid[:254]
|
target_uid = target_uid[:254]
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook captcha_factor Header"""
|
"""passbook captcha_factor Header"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook core"""
|
"""passbook core"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
"""passbook multi-factor authentication engine"""
|
"""passbook multi-factor authentication engine"""
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.forms.utils import ErrorList
|
from django.forms.utils import ErrorList
|
||||||
|
from django.shortcuts import redirect
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.views.generic import FormView
|
from django.views.generic import FormView
|
||||||
|
|
||||||
@ -21,6 +23,19 @@ class PasswordFactor(FormView, AuthenticationFactor):
|
|||||||
form_class = PasswordFactorForm
|
form_class = PasswordFactorForm
|
||||||
template_name = 'login/factors/backend.html'
|
template_name = 'login/factors/backend.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs['show_password_forget_notice'] = CONFIG.y('passbook.password_reset.enabled')
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
if 'password-forgotten' in request.GET:
|
||||||
|
# TODO: Save nonce key in database for password reset
|
||||||
|
# TODO: Send email to user
|
||||||
|
self.authenticator.cleanup()
|
||||||
|
messages.success(request, _('Check your E-Mails for a password reset link.'))
|
||||||
|
return redirect('passbook_core:auth-login')
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
"""Authenticate against django's authentication backend"""
|
"""Authenticate against django's authentication backend"""
|
||||||
uid_fields = CONFIG.y('passbook.uid_fields')
|
uid_fields = CONFIG.y('passbook.uid_fields')
|
||||||
|
|||||||
@ -111,7 +111,7 @@ class AuthenticationView(UserPassesTestMixin, View):
|
|||||||
"""Show error message, user cannot login.
|
"""Show error message, user cannot login.
|
||||||
This should only be shown if user authenticated successfully, but is disabled/locked/etc"""
|
This should only be shown if user authenticated successfully, but is disabled/locked/etc"""
|
||||||
LOGGER.debug("User invalid")
|
LOGGER.debug("User invalid")
|
||||||
self._cleanup()
|
self.cleanup()
|
||||||
return redirect(reverse('passbook_core:auth-denied'))
|
return redirect(reverse('passbook_core:auth-denied'))
|
||||||
|
|
||||||
def _user_passed(self):
|
def _user_passed(self):
|
||||||
@ -121,13 +121,13 @@ class AuthenticationView(UserPassesTestMixin, View):
|
|||||||
login(self.request, self.pending_user, backend=backend)
|
login(self.request, self.pending_user, backend=backend)
|
||||||
LOGGER.debug("Logged in user %s", self.pending_user)
|
LOGGER.debug("Logged in user %s", self.pending_user)
|
||||||
# Cleanup
|
# Cleanup
|
||||||
self._cleanup()
|
self.cleanup()
|
||||||
next_param = self.request.GET.get('next', None)
|
next_param = self.request.GET.get('next', None)
|
||||||
if next_param and is_url_absolute(next_param):
|
if next_param and is_url_absolute(next_param):
|
||||||
return redirect(next_param)
|
return redirect(next_param)
|
||||||
return redirect(reverse('passbook_core:overview'))
|
return redirect(reverse('passbook_core:overview'))
|
||||||
|
|
||||||
def _cleanup(self):
|
def cleanup(self):
|
||||||
"""Remove temporary data from session"""
|
"""Remove temporary data from session"""
|
||||||
session_keys = [self.SESSION_FACTOR, self.SESSION_PENDING_FACTORS,
|
session_keys = [self.SESSION_FACTOR, self.SESSION_PENDING_FACTORS,
|
||||||
self.SESSION_PENDING_USER, self.SESSION_USER_BACKEND, ]
|
self.SESSION_PENDING_USER, self.SESSION_USER_BACKEND, ]
|
||||||
|
|||||||
@ -11,7 +11,7 @@ class PasswordFactorForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = PasswordFactor
|
model = PasswordFactor
|
||||||
fields = GENERAL_FIELDS + ['backends']
|
fields = GENERAL_FIELDS + ['backends', 'password_policies']
|
||||||
widgets = {
|
widgets = {
|
||||||
'name': forms.TextInput(),
|
'name': forms.TextInput(),
|
||||||
'order': forms.NumberInput(),
|
'order': forms.NumberInput(),
|
||||||
|
|||||||
25
passbook/core/migrations/0011_auto_20190225_1438.py
Normal file
25
passbook/core/migrations/0011_auto_20190225_1438.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Generated by Django 2.1.7 on 2019-02-25 14:38
|
||||||
|
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('passbook_core', '0010_auto_20190224_1016'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='passwordfactor',
|
||||||
|
name='password_policies',
|
||||||
|
field=models.ManyToManyField(blank=True, to='passbook_core.Policy'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='user',
|
||||||
|
name='password_change_date',
|
||||||
|
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -9,9 +9,11 @@ from django.contrib.auth.models import AbstractUser
|
|||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
from django.utils.timezone import now
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from model_utils.managers import InheritanceManager
|
from model_utils.managers import InheritanceManager
|
||||||
|
|
||||||
|
from passbook.core.signals import password_changed
|
||||||
from passbook.lib.models import CreatedUpdatedModel, UUIDModel
|
from passbook.lib.models import CreatedUpdatedModel, UUIDModel
|
||||||
|
|
||||||
LOGGER = getLogger(__name__)
|
LOGGER = getLogger(__name__)
|
||||||
@ -38,6 +40,12 @@ class User(AbstractUser):
|
|||||||
sources = models.ManyToManyField('Source', through='UserSourceConnection')
|
sources = models.ManyToManyField('Source', through='UserSourceConnection')
|
||||||
applications = models.ManyToManyField('Application')
|
applications = models.ManyToManyField('Application')
|
||||||
groups = models.ManyToManyField('Group')
|
groups = models.ManyToManyField('Group')
|
||||||
|
password_change_date = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
def set_password(self, password):
|
||||||
|
password_changed.send(sender=self, user=self, password=password)
|
||||||
|
self.password_change_date = now()
|
||||||
|
return super().set_password(password)
|
||||||
|
|
||||||
class Provider(models.Model):
|
class Provider(models.Model):
|
||||||
"""Application-independent Provider instance. For example SAML2 Remote, OAuth2 Application"""
|
"""Application-independent Provider instance. For example SAML2 Remote, OAuth2 Application"""
|
||||||
@ -87,6 +95,7 @@ class PasswordFactor(Factor):
|
|||||||
"""Password-based Django-backend Authentication Factor"""
|
"""Password-based Django-backend Authentication Factor"""
|
||||||
|
|
||||||
backends = ArrayField(models.TextField())
|
backends = ArrayField(models.TextField())
|
||||||
|
password_policies = models.ManyToManyField('Policy', blank=True)
|
||||||
|
|
||||||
type = 'passbook.core.auth.factors.password.PasswordFactor'
|
type = 'passbook.core.auth.factors.password.PasswordFactor'
|
||||||
form = 'passbook.core.forms.factors.PasswordFactorForm'
|
form = 'passbook.core.forms.factors.PasswordFactorForm'
|
||||||
@ -94,6 +103,13 @@ class PasswordFactor(Factor):
|
|||||||
def has_user_settings(self):
|
def has_user_settings(self):
|
||||||
return _('Change Password'), 'pficon-key', 'passbook_core:user-change-password'
|
return _('Change Password'), 'pficon-key', 'passbook_core:user-change-password'
|
||||||
|
|
||||||
|
def password_passes(self, user: User) -> bool:
|
||||||
|
"""Return true if user's password passes, otherwise False or raise Exception"""
|
||||||
|
for policy in self.policies.all():
|
||||||
|
if not policy.passes(user):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Password Factor %s" % self.slug
|
return "Password Factor %s" % self.slug
|
||||||
|
|
||||||
@ -155,10 +171,15 @@ class Source(PolicyModel):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_url(self):
|
def get_login_button(self):
|
||||||
"""Return URL used for logging in"""
|
"""Return a tuple of URL, Icon name and Name"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def additional_info(self):
|
||||||
|
"""Return additional Info, such as a callback URL. Show in the administration interface."""
|
||||||
|
return None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,7 @@ INSTALLED_APPS = [
|
|||||||
'passbook.saml_idp.apps.PassbookSAMLIDPConfig',
|
'passbook.saml_idp.apps.PassbookSAMLIDPConfig',
|
||||||
'passbook.otp.apps.PassbookOTPConfig',
|
'passbook.otp.apps.PassbookOTPConfig',
|
||||||
'passbook.captcha_factor.apps.PassbookCaptchaFactorConfig',
|
'passbook.captcha_factor.apps.PassbookCaptchaFactorConfig',
|
||||||
|
'passbook.hibp_policy.apps.PassbookHIBPConfig',
|
||||||
]
|
]
|
||||||
|
|
||||||
# Message Tag fix for bootstrap CSS Classes
|
# Message Tag fix for bootstrap CSS Classes
|
||||||
|
|||||||
@ -9,3 +9,4 @@ from django.core.signals import Signal
|
|||||||
user_signed_up = Signal(providing_args=['request', 'user'])
|
user_signed_up = Signal(providing_args=['request', 'user'])
|
||||||
invitation_created = Signal(providing_args=['request', 'invitation'])
|
invitation_created = Signal(providing_args=['request', 'invitation'])
|
||||||
invitation_used = Signal(providing_args=['request', 'invitation', 'user'])
|
invitation_used = Signal(providing_args=['request', 'invitation', 'user'])
|
||||||
|
password_changed = Signal(providing_args=['user', 'password'])
|
||||||
|
|||||||
@ -23,16 +23,16 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
<div class="toast-notifications-list-pf">
|
||||||
|
{% include 'partials/messages.html' %}
|
||||||
|
</div>
|
||||||
<div class="login-pf-page">
|
<div class="login-pf-page">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 col-md-offset-3">
|
|
||||||
{% include 'partials/messages.html' %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 col-sm-offset-3 col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4">
|
<div class="col-sm-6 col-sm-offset-3 col-md-6 col-md-offset-3 col-lg-4 col-lg-offset-4">
|
||||||
<header class="login-pf-page-header">
|
<header class="login-pf-page-header">
|
||||||
<img class="login-pf-brand" style="max-height: 10rem;" src="{% static 'img/logo.svg' %}"
|
<img class="login-pf-brand" style="max-height: 10rem;" src="{% static 'img/logo.svg' %}"
|
||||||
alt="PatternFly logo" />
|
alt="passbook logo" />
|
||||||
{% if config.login.subtext %}
|
{% if config.login.subtext %}
|
||||||
<p>{{ config.login.subtext }}</p>
|
<p>{{ config.login.subtext }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -2,3 +2,8 @@
|
|||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block beneath_form %}
|
||||||
|
{% if show_password_forget_notice %}
|
||||||
|
<a href="{% url 'passbook_core:auth-process' %}?password-forgotten">{% trans 'Forgot password?' %}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@ -8,10 +8,11 @@
|
|||||||
<h1>{% trans title %}</h1>
|
<h1>{% trans title %}</h1>
|
||||||
</header>
|
</header>
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
{% csrf_token %}
|
|
||||||
{% block above_form %}
|
{% block above_form %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% include 'partials/form_login.html' %}
|
{% include 'partials/form_login.html' %}
|
||||||
|
{% block beneath_form %}
|
||||||
|
{% endblock %}
|
||||||
<button type="submit" class="btn btn-primary btn-block btn-lg">{% trans primary_action %}</button>
|
<button type="submit" class="btn btn-primary btn-block btn-lg">{% trans primary_action %}</button>
|
||||||
</form>
|
</form>
|
||||||
{% if show_sign_up_notice %}
|
{% if show_sign_up_notice %}
|
||||||
|
|||||||
@ -1,131 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<!--[if IE 9]><html lang="en-us" class="ie9 login-pf"><![endif]-->
|
|
||||||
<!--[if gt IE 9]><!-->
|
|
||||||
<html lang="en-us" class="login-pf">
|
|
||||||
<!--<![endif]-->
|
|
||||||
<head>
|
|
||||||
<title>Login Social Account (two column) - Red Hat® Common User Experience</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="shortcut icon" href="{% static 'img/favicon.ico' %}">
|
|
||||||
<!-- iPad retina icon -->
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="{% static 'img/apple-touch-icon-precomposed-152.png' %}">
|
|
||||||
<!-- iPad retina icon (iOS < 7) -->
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="{% static 'img/apple-touch-icon-precomposed-144.png' %}">
|
|
||||||
<!-- iPad non-retina icon -->
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="{% static 'img/apple-touch-icon-precomposed-76.png' %}">
|
|
||||||
<!-- iPad non-retina icon (iOS < 7) -->
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="{% static 'img/apple-touch-icon-precomposed-72.png' %}">
|
|
||||||
<!-- iPhone 6 Plus icon -->
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="{% static 'img/apple-touch-icon-precomposed-180.png' %}">
|
|
||||||
<!-- iPhone retina icon (iOS < 7) -->
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="{% static 'img/apple-touch-icon-precomposed-114.png' %}">
|
|
||||||
<!-- iPhone non-retina icon (iOS < 7) -->
|
|
||||||
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="{% static 'img/apple-touch-icon-precomposed-57.png' %}">
|
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'css/patternfly.min.css' %}">
|
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'css/patternfly-additions.min.css' %}">
|
|
||||||
|
|
||||||
<script src="{% static 'js/jquery.min.js' %}"></script>
|
|
||||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
|
||||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.12.2/js/bootstrap-select.min.js"></script>
|
|
||||||
<script src="{% static 'js/patternfly.min.js' %}"></script>
|
|
||||||
</head>
|
|
||||||
<div class="toast-notifications-list-pf">
|
|
||||||
<div class="toast-pf alert alert-warning alert-dismissable">
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">
|
|
||||||
<span class="pficon pficon-close"></span>
|
|
||||||
</button>
|
|
||||||
<span class="pficon pficon-warning-triangle-o"></span>
|
|
||||||
These examples are included for development testing purposes. For official documentation, see <a href="https://www.patternfly.org" class="alert-link">https://www.patternfly.org</a> and <a href="http://getbootstrap.com" class="alert-link">http://getbootstrap.com</a>.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="login-pf-page login-pf-page-accounts">
|
|
||||||
<header class="login-pf-page-header">
|
|
||||||
<img class="login-pf-brand" src="/" alt="Red Hat® logo" />
|
|
||||||
</header>
|
|
||||||
<div class="card-pf login-pf-accounts">
|
|
||||||
<header class="login-pf-header">
|
|
||||||
<select class="selectpicker">
|
|
||||||
<option>English</option>
|
|
||||||
<option>French</option>
|
|
||||||
<option>Italian</option>
|
|
||||||
</select>
|
|
||||||
<h1>Log In to Your Account</h1>
|
|
||||||
</header>
|
|
||||||
<section class="login-pf-social-section" role="contentinfo" aria-label="Log in to your patternfly account">
|
|
||||||
<form>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="sr-only" for="exampleInputEmail1">Email address</label>
|
|
||||||
<input type="email" class="form-control input-lg" id="exampleInputEmail1" placeholder="Email address">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="sr-only" for="exampleInputPassword1">Password
|
|
||||||
</label>
|
|
||||||
<input type="password" class="form-control input-lg" id="exampleInputPassword1" placeholder="Password">
|
|
||||||
</div>
|
|
||||||
<div class="login-pf-settings">
|
|
||||||
<label class="checkbox-label">
|
|
||||||
<input type="checkbox"> Keep me logged in for 30 days
|
|
||||||
</label>
|
|
||||||
<a href="#">Forgot password?</a>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary btn-block btn-lg">Log In</button>
|
|
||||||
</form>
|
|
||||||
</section><!--login-pf-section-->
|
|
||||||
<section class="login-pf-social-section" role="contentinfo" aria-label="Log in with third party account">
|
|
||||||
<ul class="login-pf-social login-pf-social-double-col list-unstyled">
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/google-logo.svg' %}" alt="Google account login">Google</a></li>
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/github-logo.svg' %}" alt="github account login">Github</a></li>
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/facebook-logo.svg' %}" alt="Facebook account login">Facebook</a></li>
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/twitter-logo.svg' %}" alt="Twitter account login">Twitter</a></li>
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/linkedin-logo.svg' %}" alt="LinkIn account login">LinkIn</a></li>
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/stack-exchange-logo.svg' %}" alt="Stack Exchange logo">Stack Exchange</a></li>
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/open-id-logo.svg' %}" alt="Open ID account login">Open ID</a></li>
|
|
||||||
<li class="login-pf-social-link"><a href="#"><img src="{% static 'img/instagram-logo.png' %}" alt="Instagram account login">Instagram</a></li>
|
|
||||||
<li class="login-pf-social-link login-pf-social-link-more"><a href="#"><img src="{% static 'img/git-logo.svg' %}" alt="Git account login">Git</a></li>
|
|
||||||
<li class="login-pf-social-link login-pf-social-link-more"><a href="#"><img src="{% static 'img/dropbox-logo.svg' %}" alt="dropbox account login">Dropbox</a></li>
|
|
||||||
<li class="login-pf-social-link login-pf-social-link-more"><a href="#"><img src="{% static 'img/fedora-logo.png' %}" alt="fedora account login">Fedora</a></li>
|
|
||||||
<li class="login-pf-social-link login-pf-social-link-more"><a href="#"><img src="{% static 'img/skype-logo.svg' %}" alt="skype account logingit ">Skype</a></li>
|
|
||||||
</ul>
|
|
||||||
<button type="button" id="socialAccountsToggle" class="btn btn-link login-pf-social-toggle">More<span class="caret"></span></button>
|
|
||||||
</section><!--login-pf-section-->
|
|
||||||
<p class="login-pf-signup">Need an account?<a href="#">Sign up</a></p>
|
|
||||||
</div><!-- card -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 col-md-offset-3">
|
|
||||||
<footer class="login-pf-page-footer">
|
|
||||||
<ul class="login-pf-page-footer-links list-unstyled">
|
|
||||||
<li><a class="login-pf-page-footer-link" href="#">Terms of Use</a></li>
|
|
||||||
<li><a class="login-pf-page-footer-link" href="#">Help</a></li>
|
|
||||||
<li><a class="login-pf-page-footer-link" href="#">Privacy Policy</a></li>
|
|
||||||
</ul>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- login-pf-page -->
|
|
||||||
<script>
|
|
||||||
$("#socialAccountsToggle").on("click", function(e) {
|
|
||||||
var $toggle = $(e.target);
|
|
||||||
var text = $toggle.contents().first()[0];
|
|
||||||
var socialContainer = $('.login-pf-social-section > .login-pf-social');
|
|
||||||
|
|
||||||
if ($toggle.hasClass('login-pf-social-toggle-active')) {
|
|
||||||
$toggle.removeClass('login-pf-social-toggle-active');
|
|
||||||
text.textContent = 'More';
|
|
||||||
socialContainer.removeClass('login-pf-social-all');
|
|
||||||
} else {
|
|
||||||
$toggle.addClass('login-pf-social-toggle-active');
|
|
||||||
text.textContent = 'Less';
|
|
||||||
socialContainer.addClass('login-pf-social-all');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,45 +1,71 @@
|
|||||||
{% extends 'login/base.html' %}
|
{% extends 'base/skeleton.html' %}
|
||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block row %}
|
{% block head %}
|
||||||
|
<style>
|
||||||
|
.login-pf-page .login-pf-page-footer-links {
|
||||||
|
padding: 15px;
|
||||||
|
background-color: #fff;
|
||||||
|
border-top: 2px solid transparent;
|
||||||
|
box-shadow: 0 1px 1px rgba(3, 3, 3, .175);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-pf-page .login-pf-page-footer-link {
|
||||||
|
color: #72767b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-pf-page .login-pf-page-footer-links li:not(:last-of-type):after {
|
||||||
|
color: #72767b;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="toast-notifications-list-pf">
|
||||||
{% include 'partials/messages.html' %}
|
{% include 'partials/messages.html' %}
|
||||||
<div class="col-md-6">
|
</div>
|
||||||
<div class="card-pf">
|
<div class="login-pf-page login-pf-page-accounts">
|
||||||
|
<header class="login-pf-page-header">
|
||||||
|
<img class="login-pf-brand" style="max-height: 10rem;" src="{% static 'img/logo.svg' %}" alt="passbook logo" />
|
||||||
|
{% if config.login.subtext %}
|
||||||
|
<p>{{ config.login.subtext }}</p>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
<div class="card-pf login-pf-accounts">
|
||||||
<header class="login-pf-header">
|
<header class="login-pf-header">
|
||||||
<h1>{% trans title %}</h1>
|
<h1>{% trans title %}</h1>
|
||||||
</header>
|
</header>
|
||||||
|
<section class="login-pf-social-section" role="contentinfo" aria-label="Log in to your patternfly account">
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
{% csrf_token %}
|
|
||||||
{% block above_form %}
|
{% block above_form %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% include 'partials/form_login.html' %}
|
{% include 'partials/form_login.html' %}
|
||||||
<button type="submit" class="btn btn-primary btn-block btn-lg">{% trans primary_action %}</button>
|
<button type="submit" class="btn btn-primary btn-block btn-lg">{% trans primary_action %}</button>
|
||||||
</form>
|
</form>
|
||||||
|
</section>
|
||||||
|
<!--login-pf-section-->
|
||||||
|
<section class="login-pf-social-section" role="contentinfo" aria-label="Log in with third party account">
|
||||||
|
<ul class="login-pf-social login-pf-social-double-col list-unstyled">
|
||||||
|
{% for url, icon, name in sources %}
|
||||||
|
<li class="login-pf-social-link">
|
||||||
|
<a href="{{ url }}">
|
||||||
|
<img src="{% static 'img/' %}{{ icon }}.svg" alt="{{ name }}"> {{ name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
{% if show_sign_up_notice %}
|
{% if show_sign_up_notice %}
|
||||||
<p class="login-pf-signup">
|
<p class="login-pf-signup">
|
||||||
{% trans 'Need an account?' %}
|
{% trans 'Need an account?' %}
|
||||||
<a href="{% url 'passbook_core:auth-sign-up' %}">{% trans 'Sign up' %}</a>
|
<a href="{% url 'passbook_core:auth-sign-up' %}">{% trans 'Sign up' %}</a>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div><!-- card -->
|
||||||
</div>
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6 col-md-offset-3">
|
||||||
<div class="card-pf">
|
|
||||||
<header class="login-pf-header">
|
|
||||||
<h1>{% trans title %}</h1>
|
|
||||||
<ul>
|
|
||||||
{% for source in sources %}
|
|
||||||
<li>
|
|
||||||
<a class="btn btn-block btn-primary" href="{{ source.get_url }}">{{ source }}</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</header>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2">
|
|
||||||
<footer class="login-pf-page-footer">
|
<footer class="login-pf-page-footer">
|
||||||
<ul class="login-pf-page-footer-links list-unstyled">
|
<ul class="login-pf-page-footer-links list-unstyled">
|
||||||
<li><a class="login-pf-page-footer-link" href="#">Terms of Use</a></li>
|
<li><a class="login-pf-page-footer-link" href="#">Terms of Use</a></li>
|
||||||
@ -48,4 +74,6 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -5,6 +5,9 @@
|
|||||||
{% load is_active %}
|
{% load is_active %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
<div class="toast-notifications-list-pf">
|
||||||
|
{% include 'partials/messages.html' %}
|
||||||
|
</div>
|
||||||
<nav class="navbar navbar-default navbar-pf" role="navigation">
|
<nav class="navbar navbar-default navbar-pf" role="navigation">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse-1">
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse-1">
|
||||||
@ -20,8 +23,8 @@
|
|||||||
<div class="collapse navbar-collapse navbar-collapse-1">
|
<div class="collapse navbar-collapse navbar-collapse-1">
|
||||||
<ul class="nav navbar-nav navbar-utility">
|
<ul class="nav navbar-nav navbar-utility">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<button class="btn btn-link nav-item-iconic" id="horizontalDropdownMenu1" data-toggle="dropdown" aria-haspopup="true"
|
<button class="btn btn-link nav-item-iconic" id="horizontalDropdownMenu1" data-toggle="dropdown"
|
||||||
aria-expanded="true">
|
aria-haspopup="true" aria-expanded="true">
|
||||||
<span title="Help" class="fa pficon-help dropdown-title"></span>
|
<span title="Help" class="fa pficon-help dropdown-title"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="horizontalDropdownMenu1">
|
<ul class="dropdown-menu" aria-labelledby="horizontalDropdownMenu1">
|
||||||
@ -66,9 +69,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container-fluid container-cards-pf">
|
<div class="container-fluid container-cards-pf">
|
||||||
<div class="container">
|
|
||||||
{% include 'partials/messages.html' %}
|
|
||||||
</div>
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -25,9 +25,6 @@
|
|||||||
<label class="checkbox-label">
|
<label class="checkbox-label">
|
||||||
{{ field }} {{ field.label }}
|
{{ field }} {{ field.label }}
|
||||||
</label>
|
</label>
|
||||||
{% if show_password_forget_notice %}
|
|
||||||
<a href="#">{% trans 'Forgot password?' %}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<label class="col-sm-2 sr-only" {% if field.field.required %}class="required"{% endif %} for="{{ field.name }}-{{ forloop.counter0 }}">
|
<label class="col-sm-2 sr-only" {% if field.field.required %}class="required"{% endif %} for="{{ field.name }}-{{ forloop.counter0 }}">
|
||||||
{{ field.label }}
|
{{ field.label }}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for msg in messages %}
|
{% for msg in messages %}
|
||||||
<div class="alert alert-{{ msg.level_tag }}">
|
<div class="toast-pf alert alert-dismissable alert-{{ msg.level_tag }}">
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||||
<span class="pficon pficon-close"></span>
|
<span class="pficon pficon-close"></span>
|
||||||
</button>
|
</button>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
{% elif msg.level_tag == 'info' %}
|
{% elif msg.level_tag == 'info' %}
|
||||||
<span class="pficon pficon-info"></span>
|
<span class="pficon pficon-info"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<strong>{{ msg.message|safe }}</strong>
|
{{ msg.message|safe }}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
0
passbook/core/tests/__init__.py
Normal file
0
passbook/core/tests/__init__.py
Normal file
10
passbook/core/tests/test_login.py
Normal file
10
passbook/core/tests/test_login.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
"""passbook core login test"""
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class LoginTest(TestCase):
|
||||||
|
"""Test login"""
|
||||||
|
|
||||||
|
def test(self):
|
||||||
|
"""Stub test"""
|
||||||
@ -41,10 +41,12 @@ class LoginView(UserPassesTestMixin, FormView):
|
|||||||
kwargs['title'] = _('Log in to your account')
|
kwargs['title'] = _('Log in to your account')
|
||||||
kwargs['primary_action'] = _('Log in')
|
kwargs['primary_action'] = _('Log in')
|
||||||
kwargs['show_sign_up_notice'] = CONFIG.y('passbook.sign_up.enabled')
|
kwargs['show_sign_up_notice'] = CONFIG.y('passbook.sign_up.enabled')
|
||||||
kwargs['show_password_forget_notice'] = CONFIG.y('passbook.password_reset.enabled')
|
kwargs['sources'] = []
|
||||||
kwargs['sources'] = Source.objects.filter(enabled=True).select_subclasses()
|
sources = Source.objects.filter(enabled=True).select_subclasses()
|
||||||
if any(source.is_link for source in kwargs['sources']):
|
if any(source.is_link for source in sources):
|
||||||
self.template_name = 'login/test.html'
|
for source in sources:
|
||||||
|
kwargs['sources'].append(source.get_login_button)
|
||||||
|
self.template_name = 'login/with_sources.html'
|
||||||
return super().get_context_data(**kwargs)
|
return super().get_context_data(**kwargs)
|
||||||
|
|
||||||
def get_user(self, uid_value) -> User:
|
def get_user(self, uid_value) -> User:
|
||||||
|
|||||||
2
passbook/hibp_policy/__init__.py
Normal file
2
passbook/hibp_policy/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
"""passbook hibp_policy"""
|
||||||
|
__version__ = '0.0.7-alpha'
|
||||||
5
passbook/hibp_policy/admin.py
Normal file
5
passbook/hibp_policy/admin.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
"""Passbook HIBP Admin"""
|
||||||
|
|
||||||
|
from passbook.lib.admin import admin_autoregister
|
||||||
|
|
||||||
|
admin_autoregister('passbook_hibp_policy')
|
||||||
11
passbook/hibp_policy/apps.py
Normal file
11
passbook/hibp_policy/apps.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
"""Passbook hibp app config"""
|
||||||
|
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PassbookHIBPConfig(AppConfig):
|
||||||
|
"""Passbook hibp app config"""
|
||||||
|
|
||||||
|
name = 'passbook.hibp_policy'
|
||||||
|
label = 'passbook_hibp_policy'
|
||||||
|
verbose_name = 'passbook HaveIBeenPwned Policy'
|
||||||
19
passbook/hibp_policy/forms.py
Normal file
19
passbook/hibp_policy/forms.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
"""passbook HaveIBeenPwned Policy forms"""
|
||||||
|
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
from passbook.core.forms.policies import GENERAL_FIELDS
|
||||||
|
from passbook.hibp_policy.models import HaveIBeenPwendPolicy
|
||||||
|
|
||||||
|
|
||||||
|
class HaveIBeenPwnedPolicyForm(forms.ModelForm):
|
||||||
|
"""Edit HaveIBeenPwendPolicy instances"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = HaveIBeenPwendPolicy
|
||||||
|
fields = GENERAL_FIELDS + ['allowed_count']
|
||||||
|
widgets = {
|
||||||
|
'name': forms.TextInput(),
|
||||||
|
'order': forms.NumberInput(),
|
||||||
|
}
|
||||||
28
passbook/hibp_policy/migrations/0001_initial.py
Normal file
28
passbook/hibp_policy/migrations/0001_initial.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Generated by Django 2.1.7 on 2019-02-25 15:50
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('passbook_core', '0011_auto_20190225_1438'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='HaveIBeenPwendPolicy',
|
||||||
|
fields=[
|
||||||
|
('policy_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='passbook_core.Policy')),
|
||||||
|
('allowed_count', models.IntegerField(default=0)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'HaveIBeenPwned Policy',
|
||||||
|
'verbose_name_plural': 'HaveIBeenPwned Policies',
|
||||||
|
},
|
||||||
|
bases=('passbook_core.policy',),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
passbook/hibp_policy/migrations/__init__.py
Normal file
0
passbook/hibp_policy/migrations/__init__.py
Normal file
43
passbook/hibp_policy/models.py
Normal file
43
passbook/hibp_policy/models.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
"""passbook HIBP Models"""
|
||||||
|
|
||||||
|
from hashlib import sha1
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
from requests import get
|
||||||
|
|
||||||
|
from passbook.core.models import Policy, User
|
||||||
|
|
||||||
|
|
||||||
|
class HaveIBeenPwendPolicy(Policy):
|
||||||
|
"""Check if password is on HaveIBeenPwned's list by upload the first
|
||||||
|
5 characters of the SHA1 Hash."""
|
||||||
|
|
||||||
|
allowed_count = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
form = 'passbook.hibp_policy.forms.HaveIBeenPwnedPolicyForm'
|
||||||
|
|
||||||
|
def passes(self, user: User) -> bool:
|
||||||
|
"""Check if password is in HIBP DB. Hashes given Password with SHA1, uses the first 5
|
||||||
|
characters of Password in request and checks if full hash is in response. Returns 0
|
||||||
|
if Password is not in result otherwise the count of how many times it was used."""
|
||||||
|
# Only check if password is being set
|
||||||
|
if not hasattr(user, '__password__'):
|
||||||
|
return True
|
||||||
|
password = getattr(user, '__password__')
|
||||||
|
pw_hash = sha1(password.encode('utf-8')).hexdigest() # nosec
|
||||||
|
url = 'https://api.pwnedpasswords.com/range/%s' % pw_hash[:5]
|
||||||
|
result = get(url).text
|
||||||
|
final_count = 0
|
||||||
|
for line in result.split('\r\n'):
|
||||||
|
full_hash, count = line.split(':')
|
||||||
|
if pw_hash[5:] == full_hash.lower():
|
||||||
|
final_count = int(count)
|
||||||
|
if final_count > self.allowed_count:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _('have i been pwned Policy')
|
||||||
|
verbose_name_plural = _('have i been pwned Policies')
|
||||||
@ -1,2 +1,2 @@
|
|||||||
"""Passbook ldap app Header"""
|
"""Passbook ldap app Header"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class LDAPSource(Source):
|
|||||||
form = 'passbook.ldap.forms.LDAPSourceForm'
|
form = 'passbook.ldap.forms.LDAPSourceForm'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_url(self):
|
def get_login_button(self):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook lib"""
|
"""passbook lib"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook oauth_client Header"""
|
"""passbook oauth_client Header"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -26,8 +26,16 @@ class OAuthSource(Source):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def get_url(self):
|
def get_login_button(self):
|
||||||
return reverse_lazy('passbook_oauth_client:oauth-client-login',
|
url = reverse_lazy('passbook_oauth_client:oauth-client-login',
|
||||||
|
kwargs={'source_slug': self.slug})
|
||||||
|
if self.provider_type == 'github':
|
||||||
|
return url, 'github-logo', _('GitHub')
|
||||||
|
return url, 'generic', _('Generic')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def additional_info(self):
|
||||||
|
return "Callback URL: '%s'" % reverse_lazy('passbook_oauth_client:oauth-client-callback',
|
||||||
kwargs={'source_slug': self.slug})
|
kwargs={'source_slug': self.slug})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook oauth_provider Header"""
|
"""passbook oauth_provider Header"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook otp Header"""
|
"""passbook otp Header"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook saml_idp Header"""
|
"""passbook saml_idp Header"""
|
||||||
__version__ = '0.0.7-alpha'
|
__version__ = '0.0.8-alpha'
|
||||||
|
|||||||
Reference in New Issue
Block a user