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,33 +9,35 @@ | |||||||
|  |  | ||||||
| {% 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"> | ||||||
|     {% trans 'Create...' %} |         {% trans 'Create...' %} | ||||||
|   </a> |     </a> | ||||||
|   <hr> |     <hr> | ||||||
|   <table class="table table-striped table-bordered"> |     <table class="table table-striped table-bordered"> | ||||||
|     <thead> |         <thead> | ||||||
|       <tr> |             <tr> | ||||||
|         <th>{% trans 'Name' %}</th> |                 <th>{% trans 'Name' %}</th> | ||||||
|         <th>{% trans 'Provider' %}</th> |                 <th>{% trans 'Provider' %}</th> | ||||||
|         <th></th> |                 <th></th> | ||||||
|       </tr> |             </tr> | ||||||
|     </thead> |         </thead> | ||||||
|     <tbody> |         <tbody> | ||||||
|       {% for application in object_list %} |             {% for application in object_list %} | ||||||
|         <tr> |             <tr> | ||||||
|           <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> | ||||||
|           </td> |                     <a class="btn btn-default btn-sm" | ||||||
|         </tr> |                         href="{% url 'passbook_admin:application-delete' pk=application.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> | ||||||
|       {% endfor %} |                 </td> | ||||||
|     </tbody> |             </tr> | ||||||
|   </table> |             {% endfor %} | ||||||
|  |         </tbody> | ||||||
|  |     </table> | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -8,80 +8,80 @@ | |||||||
| {% 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"> | ||||||
|       <div class="list-view-pf-main-info"> |         <div class="list-view-pf-main-info"> | ||||||
|         <div class="list-view-pf-left"> |             <div class="list-view-pf-left"> | ||||||
|           <span class="fa fa-plane list-view-pf-icon-sm"></span> |                 <span class="fa fa-plane list-view-pf-icon-sm"></span> | ||||||
|  |             </div> | ||||||
|  |             <div class="list-view-pf-body"> | ||||||
|  |                 <div class="list-view-pf-description"> | ||||||
|  |                     <div class="list-group-item-heading"> | ||||||
|  |                         {{ entry.action }} | ||||||
|  |                     </div> | ||||||
|  |                     <div class="list-group-item-text"> | ||||||
|  |                         {{ entry.context }} | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="list-view-pf-additional-info"> | ||||||
|  |                     <div class="list-view-pf-additional-info-item"> | ||||||
|  |                         <span class="pficon pficon-user"></span> | ||||||
|  |                         <strong>{{ entry.user }}</strong> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="list-view-pf-additional-info-item"> | ||||||
|  |                         <span class="pficon pficon-cluster"></span> | ||||||
|  |                         <strong>{{ entry.app|default:'-' }}</strong> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="list-view-pf-additional-info-item"> | ||||||
|  |                         <span class="fa fa-clock-o"></span> | ||||||
|  |                         <strong>{{ entry.created }}</strong> | ||||||
|  |                     </div> | ||||||
|  |                     <div class="list-view-pf-additional-info-item"> | ||||||
|  |                         <span class="pficon pficon-screen"></span> | ||||||
|  |                         <strong>{{ entry.request_ip }}</strong> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <div class="list-view-pf-body"> |  | ||||||
|           <div class="list-view-pf-description"> |  | ||||||
|             <div class="list-group-item-heading"> |  | ||||||
|               {{ entry.action }} |  | ||||||
|             </div> |  | ||||||
|             <div class="list-group-item-text"> |  | ||||||
|               {{ entry.context }} |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|           <div class="list-view-pf-additional-info"> |  | ||||||
|             <div class="list-view-pf-additional-info-item"> |  | ||||||
|                 <span class="pficon pficon-user"></span> |  | ||||||
|                 <strong>{{ entry.user }}</strong> |  | ||||||
|             </div> |  | ||||||
|             <div class="list-view-pf-additional-info-item"> |  | ||||||
|                 <span class="pficon pficon-cluster"></span> |  | ||||||
|                 <strong>{{ entry.app|default:'-' }}</strong> |  | ||||||
|             </div> |  | ||||||
|             <div class="list-view-pf-additional-info-item"> |  | ||||||
|                 <span class="fa fa-clock-o"></span> |  | ||||||
|                 <strong>{{ entry.created }}</strong> |  | ||||||
|             </div> |  | ||||||
|             <div class="list-view-pf-additional-info-item"> |  | ||||||
|                 <span class="pficon pficon-screen"></span> |  | ||||||
|                 <strong>{{ entry.request_ip }}</strong> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </div> |     </div> | ||||||
|     {% endfor %} |     {% endfor %} | ||||||
|   <script> |     <script> | ||||||
|     $(document).ready(function () { |         $(document).ready(function () { | ||||||
|       // Row Checkbox Selection |             // Row Checkbox Selection | ||||||
|       $("#pf-list-standard input[type='checkbox']").change(function (e) { |             $("#pf-list-standard input[type='checkbox']").change(function (e) { | ||||||
|         if ($(this).is(":checked")) { |                 if ($(this).is(":checked")) { | ||||||
|           $(this).closest('.list-group-item').addClass("active"); |                     $(this).closest('.list-group-item').addClass("active"); | ||||||
|         } else { |                 } else { | ||||||
|           $(this).closest('.list-group-item').removeClass("active"); |                     $(this).closest('.list-group-item').removeClass("active"); | ||||||
|         } |                 } | ||||||
|       }); |             }); | ||||||
|       // toggle dropdown menu |             // toggle dropdown menu | ||||||
|       $('#pf-list-standard .list-view-pf-actions').on('show.bs.dropdown', function () { |             $('#pf-list-standard .list-view-pf-actions').on('show.bs.dropdown', function () { | ||||||
|         var $this = $(this); |                 var $this = $(this); | ||||||
|         var $dropdown = $this.find('.dropdown'); |                 var $dropdown = $this.find('.dropdown'); | ||||||
|         var space = $(window).height() - $dropdown[0].getBoundingClientRect().top - $this.find('.dropdown-menu').outerHeight(true); |                 var space = $(window).height() - $dropdown[0].getBoundingClientRect().top - $this.find('.dropdown-menu').outerHeight(true); | ||||||
|         $dropdown.toggleClass('dropup', space < 10); |                 $dropdown.toggleClass('dropup', space < 10); | ||||||
|       }); |             }); | ||||||
|       // allow users to select multiple list items with shift key |             // allow users to select multiple list items with shift key | ||||||
|       $('#pf-list-standard .list-group').on('click', '.list-view-pf-checkbox>input', function (event) { |             $('#pf-list-standard .list-group').on('click', '.list-view-pf-checkbox>input', function (event) { | ||||||
|         var $list = $('.list-group'); |                 var $list = $('.list-group'); | ||||||
|         var prevIndex = $list.data('preIndex'); |                 var prevIndex = $list.data('preIndex'); | ||||||
|         var $listItems = $list.children('.list-group-item'); |                 var $listItems = $list.children('.list-group-item'); | ||||||
|         var $currentItem = $(this).closest('.list-group-item'); |                 var $currentItem = $(this).closest('.list-group-item'); | ||||||
|         if (event.shiftKey && prevIndex > -1 && this.checked) { |                 if (event.shiftKey && prevIndex > -1 && this.checked) { | ||||||
|           var currentIndex = $listItems.index($currentItem); |                     var currentIndex = $listItems.index($currentItem); | ||||||
|           var $selectScope = currentIndex - prevIndex > 0 |                     var $selectScope = currentIndex - prevIndex > 0 | ||||||
|             ? $currentItem.prevAll().not($listItems.eq(prevIndex).prevAll().addBack()) |                         ? $currentItem.prevAll().not($listItems.eq(prevIndex).prevAll().addBack()) | ||||||
|             : $listItems.eq(prevIndex).prevAll().not($currentItem.prevAll().addBack()); |                         : $listItems.eq(prevIndex).prevAll().not($currentItem.prevAll().addBack()); | ||||||
|           $selectScope.addClass('active').find('.list-view-pf-checkbox').children('input').prop('checked', true); |                     $selectScope.addClass('active').find('.list-view-pf-checkbox').children('input').prop('checked', true); | ||||||
|         } |                 } | ||||||
|         $list.data('preIndex', this.checked ? $listItems.index($currentItem) : -1); |                 $list.data('preIndex', this.checked ? $listItems.index($currentItem) : -1); | ||||||
|       }); |             }); | ||||||
|  |  | ||||||
|     }); |         }); | ||||||
|   </script> |     </script> | ||||||
|   {% include 'partials/pagination.html' %} |     {% include 'partials/pagination.html' %} | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -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,32 +9,35 @@ | |||||||
|  |  | ||||||
| {% 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"> | ||||||
|     {% trans 'Create...' %} |         {% trans 'Create...' %} | ||||||
|   </a> |     </a> | ||||||
|   <hr> |     <hr> | ||||||
|   <table class="table table-striped table-bordered"> |     <table class="table table-striped table-bordered"> | ||||||
|     <thead> |         <thead> | ||||||
|       <tr> |             <tr> | ||||||
|         <th>{% trans 'Expiry' %}</th> |                 <th>{% trans 'Expiry' %}</th> | ||||||
|         <th>{% trans 'Link' %}</th> |                 <th>{% trans 'Link' %}</th> | ||||||
|         <th></th> |                 <th></th> | ||||||
|       </tr> |             </tr> | ||||||
|     </thead> |         </thead> | ||||||
|     <tbody> |         <tbody> | ||||||
|       {% 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> |                     <pre>{{ invitation.link }}</pre> | ||||||
|             <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> |                 <td> | ||||||
|         </tr> |                     <a class="btn btn-default btn-sm" | ||||||
|       {% endfor %} |                         href="{% url 'passbook_admin:invitation-delete' pk=invitation.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> | ||||||
|     </tbody> |                 </td> | ||||||
|   </table> |             </tr> | ||||||
|  |             {% endfor %} | ||||||
|  |         </tbody> | ||||||
|  |     </table> | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -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,42 +9,46 @@ | |||||||
|  |  | ||||||
| {% 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"> | ||||||
|     <button class="btn btn-primary dropdown-toggle" type="button" id="createDropdown" data-toggle="dropdown"> |         <button class="btn btn-primary dropdown-toggle" type="button" id="createDropdown" data-toggle="dropdown"> | ||||||
|       {% trans 'Create...' %} |             {% trans 'Create...' %} | ||||||
|       <span class="caret"></span> |             <span class="caret"></span> | ||||||
|     </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" | ||||||
|       {% endfor %} |                     href="{% url 'passbook_admin:policy-create' %}?type={{ type }}">{{ name }}</a></li> | ||||||
|     </ul> |             {% endfor %} | ||||||
|   </div> |         </ul> | ||||||
|   <hr> |     </div> | ||||||
|   <table class="table table-striped table-bordered"> |     <hr> | ||||||
|     <thead> |     <table class="table table-striped table-bordered"> | ||||||
|       <tr> |         <thead> | ||||||
|         <th>{% trans 'Name' %}</th> |             <tr> | ||||||
|         <th>{% trans 'Class' %}</th> |                 <th>{% trans 'Name' %}</th> | ||||||
|         <th></th> |                 <th>{% trans 'Class' %}</th> | ||||||
|       </tr> |                 <th></th> | ||||||
|     </thead> |             </tr> | ||||||
|     <tbody> |         </thead> | ||||||
|       {% for policy in object_list %} |         <tbody> | ||||||
|         <tr> |             {% for policy in object_list %} | ||||||
|           <td>{{ policy.name }}</td> |             <tr> | ||||||
|           <td>{{ policy|fieldtype }}</td> |                 <td>{{ policy.name }}</td> | ||||||
|           <td> |                 <td>{{ policy|fieldtype }}</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> |                 <td> | ||||||
|             <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" | ||||||
|             <a class="btn btn-default btn-sm" href="{% url 'passbook_admin:policy-delete' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> |                         href="{% url 'passbook_admin:policy-update' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Edit' %}</a> | ||||||
|           </td> |                     <a class="btn btn-default btn-sm" | ||||||
|         </tr> |                         href="{% url 'passbook_admin:policy-test' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Test' %}</a> | ||||||
|       {% endfor %} |                     <a class="btn btn-default btn-sm" | ||||||
|     </tbody> |                         href="{% url 'passbook_admin:policy-delete' pk=policy.uuid %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> | ||||||
|   </table> |                 </td> | ||||||
|  |             </tr> | ||||||
|  |             {% endfor %} | ||||||
|  |         </tbody> | ||||||
|  |     </table> | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -10,45 +10,49 @@ | |||||||
|  |  | ||||||
| {% 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"> | ||||||
|     <button class="btn btn-primary dropdown-toggle" type="button" id="createDropdown" data-toggle="dropdown"> |         <button class="btn btn-primary dropdown-toggle" type="button" id="createDropdown" data-toggle="dropdown"> | ||||||
|       {% trans 'Create...' %} |             {% trans 'Create...' %} | ||||||
|       <span class="caret"></span> |             <span class="caret"></span> | ||||||
|     </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" | ||||||
|       {% endfor %} |                     href="{% url 'passbook_admin:provider-create' %}?type={{ type }}">{{ name }}</a></li> | ||||||
|     </ul> |  | ||||||
|   </div> |  | ||||||
|   <hr> |  | ||||||
|   <table class="table table-striped table-bordered"> |  | ||||||
|     <thead> |  | ||||||
|       <tr> |  | ||||||
|         <th>{% trans 'Name' %}</th> |  | ||||||
|         <th>{% trans 'Class' %}</th> |  | ||||||
|         <th></th> |  | ||||||
|       </tr> |  | ||||||
|     </thead> |  | ||||||
|     <tbody> |  | ||||||
|       {% for provider in object_list %} |  | ||||||
|         <tr> |  | ||||||
|           <td>{{ provider.name }}</td> |  | ||||||
|           <td>{{ provider|fieldtype }}</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" href="{% url 'passbook_admin:provider-delete' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> |  | ||||||
|             {% get_links provider as links %} |  | ||||||
|             {% for name, href in links.items %} |  | ||||||
|               <a class="btn btn-default btn-sm" href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a> |  | ||||||
|             {% endfor %} |             {% endfor %} | ||||||
|           </td> |         </ul> | ||||||
|         </tr> |     </div> | ||||||
|       {% endfor %} |     <hr> | ||||||
|     </tbody> |     <table class="table table-striped table-bordered"> | ||||||
|   </table> |         <thead> | ||||||
|  |             <tr> | ||||||
|  |                 <th>{% trans 'Name' %}</th> | ||||||
|  |                 <th>{% trans 'Class' %}</th> | ||||||
|  |                 <th></th> | ||||||
|  |             </tr> | ||||||
|  |         </thead> | ||||||
|  |         <tbody> | ||||||
|  |             {% for provider in object_list %} | ||||||
|  |             <tr> | ||||||
|  |                 <td>{{ provider.name }}</td> | ||||||
|  |                 <td>{{ provider|fieldtype }}</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" | ||||||
|  |                         href="{% url 'passbook_admin:provider-delete' pk=provider.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> | ||||||
|  |                     {% get_links provider as links %} | ||||||
|  |                     {% for name, href in links.items %} | ||||||
|  |                     <a class="btn btn-default btn-sm" | ||||||
|  |                         href="{{ href }}?back={{ request.get_full_path }}">{% trans name %}</a> | ||||||
|  |                     {% endfor %} | ||||||
|  |                 </td> | ||||||
|  |             </tr> | ||||||
|  |             {% endfor %} | ||||||
|  |         </tbody> | ||||||
|  |     </table> | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -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,34 +5,36 @@ | |||||||
|  |  | ||||||
| {% 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> | ||||||
|       <tr> |             <tr> | ||||||
|         <th>{% trans 'Username' %}</th> |                 <th>{% trans 'Username' %}</th> | ||||||
|         <th>{% trans 'First Name' %}</th> |                 <th>{% trans 'First Name' %}</th> | ||||||
|         <th>{% trans 'Last Name' %}</th> |                 <th>{% trans 'Last Name' %}</th> | ||||||
|         <th>{% trans 'Active' %}</th> |                 <th>{% trans 'Active' %}</th> | ||||||
|         <th>{% trans 'Last Login' %}</th> |                 <th>{% trans 'Last Login' %}</th> | ||||||
|         <th></th> |                 <th></th> | ||||||
|       </tr> |             </tr> | ||||||
|     </thead> |         </thead> | ||||||
|     <tbody> |         <tbody> | ||||||
|       {% for user in object_list %} |             {% for user in object_list %} | ||||||
|         <tr> |             <tr> | ||||||
|           <td>{{ user.username }}</td> |                 <td>{{ user.username }}</td> | ||||||
|           <td>{{ user.first_name|default:'-' }}</td> |                 <td>{{ user.first_name|default:'-' }}</td> | ||||||
|           <td>{{ user.last_name|default:'-' }}</td> |                 <td>{{ user.last_name|default:'-' }}</td> | ||||||
|           <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> | ||||||
|           </td> |                     <a class="btn btn-default btn-sm" | ||||||
|         </tr> |                         href="{% url 'passbook_admin:user-delete' pk=user.pk %}?back={{ request.get_full_path }}">{% trans 'Delete' %}</a> | ||||||
|       {% endfor %} |                 </td> | ||||||
|     </tbody> |             </tr> | ||||||
|   </table> |             {% endfor %} | ||||||
|  |         </tbody> | ||||||
|  |     </table> | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -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,51 +1,79 @@ | |||||||
| {% extends 'login/base.html' %} | {% extends 'base/skeleton.html' %} | ||||||
|  |  | ||||||
| {% load static %} | {% load static %} | ||||||
| {% load i18n %} | {% load i18n %} | ||||||
|  |  | ||||||
| {% block row %} | {% block head %} | ||||||
| {% include 'partials/messages.html' %} | <style> | ||||||
| <div class="col-md-6"> |     .login-pf-page .login-pf-page-footer-links { | ||||||
|     <div class="card-pf"> |         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' %} | ||||||
|  | </div> | ||||||
|  | <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> | ||||||
|         <form method="POST"> |         <section class="login-pf-social-section" role="contentinfo" aria-label="Log in to your patternfly account"> | ||||||
|             {% csrf_token %} |             <form method="POST"> | ||||||
|             {% 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><!-- 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> | ||||||
| </div> | </div> | ||||||
| <div class="col-md-6"> |  | ||||||
|     <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"> |  | ||||||
|         <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> |  | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -5,83 +5,83 @@ | |||||||
| {% 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"> | ||||||
|       <span class="sr-only">{% trans 'Toggle navigation' %}</span> |             <span class="sr-only">{% trans 'Toggle navigation' %}</span> | ||||||
|       <span class="icon-bar"></span> |             <span class="icon-bar"></span> | ||||||
|       <span class="icon-bar"></span> |             <span class="icon-bar"></span> | ||||||
|       <span class="icon-bar"></span> |             <span class="icon-bar"></span> | ||||||
|     </button> |  | ||||||
|     <a class="navbar-brand" href="/"> |  | ||||||
|       <img src="{% static 'img/brand.svg' %}" alt="passbook" /> |  | ||||||
|     </a> |  | ||||||
|   </div> |  | ||||||
|   <div class="collapse navbar-collapse navbar-collapse-1"> |  | ||||||
|     <ul class="nav navbar-nav navbar-utility"> |  | ||||||
|       <li class="dropdown"> |  | ||||||
|         <button class="btn btn-link nav-item-iconic" id="horizontalDropdownMenu1" data-toggle="dropdown" aria-haspopup="true" |  | ||||||
|           aria-expanded="true"> |  | ||||||
|           <span title="Help" class="fa pficon-help dropdown-title"></span> |  | ||||||
|         </button> |         </button> | ||||||
|         <ul class="dropdown-menu" aria-labelledby="horizontalDropdownMenu1"> |         <a class="navbar-brand" href="/"> | ||||||
|           {% comment %} <li><a href="#0">Help</a></li> {% endcomment %} |             <img src="{% static 'img/brand.svg' %}" alt="passbook" /> | ||||||
|           <li><a data-toggle="modal" data-target="#about-modal" href="#0">{% trans 'About' %}</a></li> |         </a> | ||||||
|  |     </div> | ||||||
|  |     <div class="collapse navbar-collapse navbar-collapse-1"> | ||||||
|  |         <ul class="nav navbar-nav navbar-utility"> | ||||||
|  |             <li class="dropdown"> | ||||||
|  |                 <button class="btn btn-link nav-item-iconic" id="horizontalDropdownMenu1" data-toggle="dropdown" | ||||||
|  |                     aria-haspopup="true" aria-expanded="true"> | ||||||
|  |                     <span title="Help" class="fa pficon-help dropdown-title"></span> | ||||||
|  |                 </button> | ||||||
|  |                 <ul class="dropdown-menu" aria-labelledby="horizontalDropdownMenu1"> | ||||||
|  |                     {% comment %} <li><a href="#0">Help</a></li> {% endcomment %} | ||||||
|  |                     <li><a data-toggle="modal" data-target="#about-modal" href="#0">{% trans 'About' %}</a></li> | ||||||
|  |                 </ul> | ||||||
|  |             </li> | ||||||
|  |             <li class="dropdown"> | ||||||
|  |                 <button class="btn btn-link dropdown-toggle" data-toggle="dropdown"> | ||||||
|  |                     <span class="pficon pficon-user"></span> | ||||||
|  |                     <span class="dropdown-title"> | ||||||
|  |                         {{ user.username }} <b class="caret"></b> | ||||||
|  |                     </span> | ||||||
|  |                 </button> | ||||||
|  |                 <ul class="dropdown-menu"> | ||||||
|  |                     <li> | ||||||
|  |                         <a href="{% url 'passbook_core:user-settings' %}">{% trans 'User Settings' %}</a> | ||||||
|  |                     </li> | ||||||
|  |                     <li> | ||||||
|  |                         <a href="{% url 'passbook_core:user-change-password' %}">{% trans 'Change Password' %}</a> | ||||||
|  |                     </li> | ||||||
|  |                     <li class="divider"></li> | ||||||
|  |                     <li> | ||||||
|  |                         <a href="{% url 'passbook_core:auth-logout' %}">{% trans 'Logout' %}</a> | ||||||
|  |                     </li> | ||||||
|  |                 </ul> | ||||||
|  |             </li> | ||||||
|         </ul> |         </ul> | ||||||
|       </li> |         {% is_active_app 'passbook_admin' as is_admin %} | ||||||
|       <li class="dropdown"> |         <ul class="nav navbar-nav navbar-primary {% if is_admin == 'active' %}persistent-secondary{% endif %}"> | ||||||
|         <button class="btn btn-link dropdown-toggle" data-toggle="dropdown"> |             <li class="{% is_active_url 'passbook_core:overview' %}"> | ||||||
|           <span class="pficon pficon-user"></span> |                 <a href="{% url 'passbook_core:overview' %}">{% trans 'Overview' %}</a> | ||||||
|           <span class="dropdown-title"> |             </li> | ||||||
|             {{ user.username }} <b class="caret"></b> |             {% if user.is_superuser %} | ||||||
|           </span> |             <li class="{% is_active_app 'passbook_admin' %}"> | ||||||
|         </button> |                 <a href="{% url 'passbook_admin:overview' %}">{% trans 'Administration' %}</a> | ||||||
|         <ul class="dropdown-menu"> |                 {% block nav_secondary %} | ||||||
|           <li> |                 {% endblock %} | ||||||
|             <a href="{% url 'passbook_core:user-settings' %}">{% trans 'User Settings' %}</a> |             </li> | ||||||
|           </li> |             {% endif %} | ||||||
|           <li> |  | ||||||
|             <a href="{% url 'passbook_core:user-change-password' %}">{% trans 'Change Password' %}</a> |  | ||||||
|           </li> |  | ||||||
|           <li class="divider"></li> |  | ||||||
|           <li> |  | ||||||
|             <a href="{% url 'passbook_core:auth-logout' %}">{% trans 'Logout' %}</a> |  | ||||||
|           </li> |  | ||||||
|         </ul> |         </ul> | ||||||
|       </li> |     </div> | ||||||
|     </ul> |  | ||||||
|     {% is_active_app 'passbook_admin' as is_admin %} |  | ||||||
|     <ul class="nav navbar-nav navbar-primary {% if is_admin == 'active' %}persistent-secondary{% endif %}"> |  | ||||||
|       <li class="{% is_active_url 'passbook_core:overview' %}"> |  | ||||||
|         <a href="{% url 'passbook_core:overview' %}">{% trans 'Overview' %}</a> |  | ||||||
|       </li> |  | ||||||
|       {% if user.is_superuser %} |  | ||||||
|       <li class="{% is_active_app 'passbook_admin' %}"> |  | ||||||
|         <a href="{% url 'passbook_admin:overview' %}">{% trans 'Administration' %}</a> |  | ||||||
|         {% block nav_secondary %} |  | ||||||
|         {% endblock %} |  | ||||||
|       </li> |  | ||||||
|       {% endif %} |  | ||||||
|     </ul> |  | ||||||
|   </div> |  | ||||||
| </nav> | </nav> | ||||||
| <div class="container-fluid container-cards-pf"> | <div class="container-fluid container-cards-pf"> | ||||||
|   <div class="container"> |     {% block content %} | ||||||
|     {% include 'partials/messages.html' %} |     {% endblock %} | ||||||
|   </div> |  | ||||||
|   {% block content %} |  | ||||||
|   {% endblock %} |  | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block scripts %} | {% block scripts %} | ||||||
| <script> | <script> | ||||||
|   $(document).ready(function () { |     $(document).ready(function () { | ||||||
|     // initialize tooltips |         // initialize tooltips | ||||||
|     $('[data-toggle="tooltip"]').tooltip(); |         $('[data-toggle="tooltip"]').tooltip(); | ||||||
|  |  | ||||||
|     // Initialize the vertical navigation |         // Initialize the vertical navigation | ||||||
|     $().setupVerticalNavigation(true); |         $().setupVerticalNavigation(true); | ||||||
|   }); |     }); | ||||||
| </script> | </script> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|  | |||||||
| @ -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,19 +1,19 @@ | |||||||
| {% 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> | ||||||
|     {% if msg.level_tag == 'danger' %} |     {% if msg.level_tag == 'danger' %} | ||||||
|       <span class="pficon pficon-error-circle-o"></span> |     <span class="pficon pficon-error-circle-o"></span> | ||||||
|     {% elif msg.level_tag == 'warning' %} |     {% elif msg.level_tag == 'warning' %} | ||||||
|       <span class="pficon pficon-warning-triangle-o"></span> |     <span class="pficon pficon-warning-triangle-o"></span> | ||||||
|     {% elif msg.level_tag == 'success' %} |     {% elif msg.level_tag == 'success' %} | ||||||
|       <span class="pficon pficon-ok"></span> |     <span class="pficon pficon-ok"></span> | ||||||
|     {% 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,9 +26,17 @@ 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}) |                            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}) | ||||||
|  |  | ||||||
|     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
	