Compare commits
	
		
			22 Commits
		
	
	
		
			version/0.
			...
			version/0.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6ed2e137a2 | |||
| 45bd63c720 | |||
| 736e13fc35 | |||
| 966fff008c | |||
| 64f15eadbd | |||
| 81b66ecdcd | |||
| 53e5cf7826 | |||
| 82654b3fd9 | |||
| 9b72c604dd | |||
| 5fb1b8044c | |||
| b8daab4377 | |||
| c5b91bdae8 | |||
| 39a208c55f | |||
| a5bfef9b6b | |||
| f1f4cbef9b | |||
| 8388120b06 | |||
| 2bf96828f1 | |||
| 22838e66fe | |||
| 484dd6de09 | |||
| b743736c26 | |||
| af91e2079b | |||
| cad1c17f14 | 
@ -1,5 +1,5 @@
 | 
				
			|||||||
[bumpversion]
 | 
					[bumpversion]
 | 
				
			||||||
current_version = 0.8.9-beta
 | 
					current_version = 0.8.12-beta
 | 
				
			||||||
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>.*)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										12
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							@ -16,11 +16,11 @@ jobs:
 | 
				
			|||||||
      - name: Building Docker Image
 | 
					      - name: Building Docker Image
 | 
				
			||||||
        run: docker build
 | 
					        run: docker build
 | 
				
			||||||
          --no-cache
 | 
					          --no-cache
 | 
				
			||||||
          -t beryju/passbook:0.8.9-beta
 | 
					          -t beryju/passbook:0.8.12-beta
 | 
				
			||||||
          -t beryju/passbook:latest
 | 
					          -t beryju/passbook:latest
 | 
				
			||||||
          -f Dockerfile .
 | 
					          -f Dockerfile .
 | 
				
			||||||
      - name: Push Docker Container to Registry (versioned)
 | 
					      - name: Push Docker Container to Registry (versioned)
 | 
				
			||||||
        run: docker push beryju/passbook:0.8.9-beta
 | 
					        run: docker push beryju/passbook:0.8.12-beta
 | 
				
			||||||
      - name: Push Docker Container to Registry (latest)
 | 
					      - name: Push Docker Container to Registry (latest)
 | 
				
			||||||
        run: docker push beryju/passbook:latest
 | 
					        run: docker push beryju/passbook:latest
 | 
				
			||||||
  build-gatekeeper:
 | 
					  build-gatekeeper:
 | 
				
			||||||
@ -37,11 +37,11 @@ jobs:
 | 
				
			|||||||
          cd gatekeeper
 | 
					          cd gatekeeper
 | 
				
			||||||
          docker build \
 | 
					          docker build \
 | 
				
			||||||
          --no-cache \
 | 
					          --no-cache \
 | 
				
			||||||
          -t beryju/passbook-gatekeeper:0.8.9-beta \
 | 
					          -t beryju/passbook-gatekeeper:0.8.12-beta \
 | 
				
			||||||
          -t beryju/passbook-gatekeeper:latest \
 | 
					          -t beryju/passbook-gatekeeper:latest \
 | 
				
			||||||
          -f Dockerfile .
 | 
					          -f Dockerfile .
 | 
				
			||||||
      - name: Push Docker Container to Registry (versioned)
 | 
					      - name: Push Docker Container to Registry (versioned)
 | 
				
			||||||
        run: docker push beryju/passbook-gatekeeper:0.8.9-beta
 | 
					        run: docker push beryju/passbook-gatekeeper:0.8.12-beta
 | 
				
			||||||
      - name: Push Docker Container to Registry (latest)
 | 
					      - name: Push Docker Container to Registry (latest)
 | 
				
			||||||
        run: docker push beryju/passbook-gatekeeper:latest
 | 
					        run: docker push beryju/passbook-gatekeeper:latest
 | 
				
			||||||
  build-static:
 | 
					  build-static:
 | 
				
			||||||
@ -66,11 +66,11 @@ jobs:
 | 
				
			|||||||
        run: docker build
 | 
					        run: docker build
 | 
				
			||||||
          --no-cache
 | 
					          --no-cache
 | 
				
			||||||
          --network=$(docker network ls | grep github | awk '{print $1}')
 | 
					          --network=$(docker network ls | grep github | awk '{print $1}')
 | 
				
			||||||
          -t beryju/passbook-static:0.8.9-beta
 | 
					          -t beryju/passbook-static:0.8.12-beta
 | 
				
			||||||
          -t beryju/passbook-static:latest
 | 
					          -t beryju/passbook-static:latest
 | 
				
			||||||
          -f static.Dockerfile .
 | 
					          -f static.Dockerfile .
 | 
				
			||||||
      - name: Push Docker Container to Registry (versioned)
 | 
					      - name: Push Docker Container to Registry (versioned)
 | 
				
			||||||
        run: docker push beryju/passbook-static:0.8.9-beta
 | 
					        run: docker push beryju/passbook-static:0.8.12-beta
 | 
				
			||||||
      - name: Push Docker Container to Registry (latest)
 | 
					      - name: Push Docker Container to Registry (latest)
 | 
				
			||||||
        run: docker push beryju/passbook-static:latest
 | 
					        run: docker push beryju/passbook-static:latest
 | 
				
			||||||
  test-release:
 | 
					  test-release:
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
apiVersion: v1
 | 
					apiVersion: v1
 | 
				
			||||||
appVersion: "0.8.9-beta"
 | 
					appVersion: "0.8.12-beta"
 | 
				
			||||||
description: A Helm chart for passbook.
 | 
					description: A Helm chart for passbook.
 | 
				
			||||||
name: passbook
 | 
					name: passbook
 | 
				
			||||||
version: "0.8.9-beta"
 | 
					version: "0.8.12-beta"
 | 
				
			||||||
icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
 | 
					icon: https://git.beryju.org/uploads/-/system/project/avatar/108/logo.png
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ spec:
 | 
				
			|||||||
      labels:
 | 
					      labels:
 | 
				
			||||||
        app.kubernetes.io/name: {{ include "passbook.name" . }}
 | 
					        app.kubernetes.io/name: {{ include "passbook.name" . }}
 | 
				
			||||||
        app.kubernetes.io/instance: {{ .Release.Name }}
 | 
					        app.kubernetes.io/instance: {{ .Release.Name }}
 | 
				
			||||||
        passbook.io/component: web
 | 
					        k8s.passbook.io/component: web
 | 
				
			||||||
    spec:
 | 
					    spec:
 | 
				
			||||||
      volumes:
 | 
					      volumes:
 | 
				
			||||||
        - name: config-volume
 | 
					        - name: config-volume
 | 
				
			||||||
 | 
				
			|||||||
@ -18,4 +18,4 @@ spec:
 | 
				
			|||||||
  selector:
 | 
					  selector:
 | 
				
			||||||
    app.kubernetes.io/name: {{ include "passbook.name" . }}
 | 
					    app.kubernetes.io/name: {{ include "passbook.name" . }}
 | 
				
			||||||
    app.kubernetes.io/instance: {{ .Release.Name }}
 | 
					    app.kubernetes.io/instance: {{ .Release.Name }}
 | 
				
			||||||
    passbook.io/component: web
 | 
					    k8s.passbook.io/component: web
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ spec:
 | 
				
			|||||||
      labels:
 | 
					      labels:
 | 
				
			||||||
        app.kubernetes.io/name: {{ include "passbook.name" . }}
 | 
					        app.kubernetes.io/name: {{ include "passbook.name" . }}
 | 
				
			||||||
        app.kubernetes.io/instance: {{ .Release.Name }}
 | 
					        app.kubernetes.io/instance: {{ .Release.Name }}
 | 
				
			||||||
        passbook.io/component: worker
 | 
					        k8s.passbook.io/component: worker
 | 
				
			||||||
    spec:
 | 
					    spec:
 | 
				
			||||||
      volumes:
 | 
					      volumes:
 | 
				
			||||||
        - name: config-volume
 | 
					        - name: config-volume
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
# This is a YAML-formatted file.
 | 
					# This is a YAML-formatted file.
 | 
				
			||||||
# Declare variables to be passed into your templates.
 | 
					# Declare variables to be passed into your templates.
 | 
				
			||||||
image:
 | 
					image:
 | 
				
			||||||
  tag: 0.8.9-beta
 | 
					  tag: 0.8.12-beta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
nameOverride: ""
 | 
					nameOverride: ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ nav:
 | 
				
			|||||||
          - Sentry: integrations/services/sentry/index.md
 | 
					          - Sentry: integrations/services/sentry/index.md
 | 
				
			||||||
          - Ansible Tower/AWX: integrations/services/tower-awx/index.md
 | 
					          - Ansible Tower/AWX: integrations/services/tower-awx/index.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
repo_name: "BeryJu.org/passbook"
 | 
					repo_name: "BeryJu/passbook"
 | 
				
			||||||
repo_url: https://github.com/BeryJu/passbook
 | 
					repo_url: https://github.com/BeryJu/passbook
 | 
				
			||||||
theme:
 | 
					theme:
 | 
				
			||||||
  name: "material"
 | 
					  name: "material"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,2 +1,2 @@
 | 
				
			|||||||
"""passbook"""
 | 
					"""passbook"""
 | 
				
			||||||
__version__ = "0.8.9-beta"
 | 
					__version__ = "0.8.12-beta"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,66 +1,68 @@
 | 
				
			|||||||
{% extends "administration/base.html" %}
 | 
					{% extends "base/page.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
{% load utils %}
 | 
					{% load utils %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					{% block page_content %}
 | 
				
			||||||
<section class="pf-c-page__main-section pf-m-light">
 | 
					<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
 | 
				
			||||||
    <div class="pf-c-content">
 | 
					    <section class="pf-c-page__main-section pf-m-light">
 | 
				
			||||||
        <h1>
 | 
					        <div class="pf-c-content">
 | 
				
			||||||
            <i class="pf-icon pf-icon-catalog"></i>
 | 
					            <h1>
 | 
				
			||||||
            {% trans 'Audit Log' %}
 | 
					                <i class="pf-icon pf-icon-catalog"></i>
 | 
				
			||||||
        </h1>
 | 
					                {% trans 'Audit Log' %}
 | 
				
			||||||
    </div>
 | 
					            </h1>
 | 
				
			||||||
</section>
 | 
					 | 
				
			||||||
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
 | 
					 | 
				
			||||||
    <div class="pf-c-card">
 | 
					 | 
				
			||||||
        <div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
 | 
					 | 
				
			||||||
            {% include 'partials/pagination.html' %}
 | 
					 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
 | 
					    </section>
 | 
				
			||||||
            <thead>
 | 
					    <section class="pf-c-page__main-section pf-m-no-padding-mobile">
 | 
				
			||||||
                <tr role="row">
 | 
					        <div class="pf-c-card">
 | 
				
			||||||
                    <th role="columnheader" scope="col">{% trans 'Action' %}</th>
 | 
					            <div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-top">
 | 
				
			||||||
                    <th role="columnheader" scope="col">{% trans 'Context' %}</th>
 | 
					                {% include 'partials/pagination.html' %}
 | 
				
			||||||
                    <th role="columnheader" scope="col">{% trans 'User' %}</th>
 | 
					            </div>
 | 
				
			||||||
                    <th role="columnheader" scope="col">{% trans 'Creation Date' %}</th>
 | 
					            <table class="pf-c-table pf-m-compact pf-m-grid-xl" role="grid">
 | 
				
			||||||
                    <th role="columnheader" scope="col">{% trans 'Client IP' %}</th>
 | 
					                <thead>
 | 
				
			||||||
                </tr>
 | 
					                    <tr role="row">
 | 
				
			||||||
            </thead>
 | 
					                        <th role="columnheader" scope="col">{% trans 'Action' %}</th>
 | 
				
			||||||
            <tbody role="rowgroup">
 | 
					                        <th role="columnheader" scope="col">{% trans 'Context' %}</th>
 | 
				
			||||||
                {% for entry in object_list %}
 | 
					                        <th role="columnheader" scope="col">{% trans 'User' %}</th>
 | 
				
			||||||
                <tr role="row">
 | 
					                        <th role="columnheader" scope="col">{% trans 'Creation Date' %}</th>
 | 
				
			||||||
                    <th role="columnheader">
 | 
					                        <th role="columnheader" scope="col">{% trans 'Client IP' %}</th>
 | 
				
			||||||
                        <div>
 | 
					                    </tr>
 | 
				
			||||||
                            <div>{{ entry.action }}</div>
 | 
					                </thead>
 | 
				
			||||||
                            <small>{{ entry.app|default:'-' }}</small>
 | 
					                <tbody role="rowgroup">
 | 
				
			||||||
                        </div>
 | 
					                    {% for entry in object_list %}
 | 
				
			||||||
                    </th>
 | 
					                    <tr role="row">
 | 
				
			||||||
                    <td role="cell">
 | 
					                        <th role="columnheader">
 | 
				
			||||||
                        <code>{{ entry.context }}</code>
 | 
					                            <div>
 | 
				
			||||||
                    </td>
 | 
					                                <div>{{ entry.action }}</div>
 | 
				
			||||||
                    <td role="cell">
 | 
					                                <small>{{ entry.app|default:'-' }}</small>
 | 
				
			||||||
                        <span>
 | 
					                            </div>
 | 
				
			||||||
                            {{ entry.user }}
 | 
					                        </th>
 | 
				
			||||||
                        </span>
 | 
					                        <td role="cell">
 | 
				
			||||||
                    </td>
 | 
					                            <code>{{ entry.context }}</code>
 | 
				
			||||||
                    <td role="cell">
 | 
					                        </td>
 | 
				
			||||||
                        <span>
 | 
					                        <td role="cell">
 | 
				
			||||||
                            {{ entry.created }}
 | 
					                            <span>
 | 
				
			||||||
                        </span>
 | 
					                                {{ entry.user }}
 | 
				
			||||||
                    </td>
 | 
					                            </span>
 | 
				
			||||||
                    <td role="cell">
 | 
					                        </td>
 | 
				
			||||||
                        <span>
 | 
					                        <td role="cell">
 | 
				
			||||||
                            {{ entry.client_ip }}
 | 
					                            <span>
 | 
				
			||||||
                        </span>
 | 
					                                {{ entry.created }}
 | 
				
			||||||
                    </td>
 | 
					                            </span>
 | 
				
			||||||
                </tr>
 | 
					                        </td>
 | 
				
			||||||
                {% endfor %}
 | 
					                        <td role="cell">
 | 
				
			||||||
            </tbody>
 | 
					                            <span>
 | 
				
			||||||
        </table>
 | 
					                                {{ entry.client_ip }}
 | 
				
			||||||
        <div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
 | 
					                            </span>
 | 
				
			||||||
            {% include 'partials/pagination.html' %}
 | 
					                        </td>
 | 
				
			||||||
 | 
					                    </tr>
 | 
				
			||||||
 | 
					                    {% endfor %}
 | 
				
			||||||
 | 
					                </tbody>
 | 
				
			||||||
 | 
					            </table>
 | 
				
			||||||
 | 
					            <div class="pf-c-toolbar" id="page-layout-table-simple-toolbar-bottom">
 | 
				
			||||||
 | 
					                {% include 'partials/pagination.html' %}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </section>
 | 
				
			||||||
</section>
 | 
					</main>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,10 @@
 | 
				
			|||||||
{% extends "overview/base.html" %}
 | 
					{% extends "base/page.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% load static %}
 | 
					{% load static %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% load is_active %}
 | 
				
			||||||
 | 
					{% load utils %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
{{ block.super }}
 | 
					{{ block.super }}
 | 
				
			||||||
@ -12,3 +16,78 @@
 | 
				
			|||||||
<script src="{% static 'node_modules/codemirror/mode/yaml/yaml.js' %}"></script>
 | 
					<script src="{% static 'node_modules/codemirror/mode/yaml/yaml.js' %}"></script>
 | 
				
			||||||
<script src="{% static 'node_modules/codemirror/mode/jinja2/jinja2.js' %}"></script>
 | 
					<script src="{% static 'node_modules/codemirror/mode/jinja2/jinja2.js' %}"></script>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block page_content %}
 | 
				
			||||||
 | 
					<div class="pf-c-page__sidebar">
 | 
				
			||||||
 | 
					    <div class="pf-c-page__sidebar-body">
 | 
				
			||||||
 | 
					        <nav class="pf-c-nav" id="page-default-nav-example-primary-nav" aria-label="Global">
 | 
				
			||||||
 | 
					            <ul class="pf-c-nav__list">
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:overview' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active_url 'passbook_admin:overview' %}">
 | 
				
			||||||
 | 
					                        {% trans 'System Status' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:applications' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:applications' 'passbook_admin:application-create' 'passbook_admin:application-update' 'passbook_admin:application-delete' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Applications' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:sources' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:sources' 'passbook_admin:source-create' 'passbook_admin:source-update' 'passbook_admin:source-delete' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Sources' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:providers' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:providers' 'passbook_admin:provider-create' 'passbook_admin:provider-update' 'passbook_admin:provider-delete' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Providers' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:property-mappings' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Property Mappings' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:factors' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:factors' 'passbook_admin:factor-create' 'passbook_admin:factor-update' 'passbook_admin:factor-delete' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Factors' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:policies' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:policies' 'passbook_admin:policy-create' 'passbook_admin:policy-update' 'passbook_admin:policy-delete' 'passbook_admin:policy-test' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Policies' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:invitations' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:invitations' 'passbook_admin:invitation-create' 'passbook_admin:invitation-update' 'passbook_admin:invitation-delete' 'passbook_admin:invitation-test' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Invitations' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:users' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:users' 'passbook_admin:user-update' 'passbook_admin:user-delete' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Users' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					                <li class="pf-c-nav__item">
 | 
				
			||||||
 | 
					                    <a href="{% url 'passbook_admin:groups' %}"
 | 
				
			||||||
 | 
					                        class="pf-c-nav__link {% is_active 'passbook_admin:groups' 'passbook_admin:group-update' 'passbook_admin:group-delete' %}">
 | 
				
			||||||
 | 
					                        {% trans 'Groups' %}
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                </li>
 | 
				
			||||||
 | 
					            </ul>
 | 
				
			||||||
 | 
					        </nav>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
 | 
				
			||||||
 | 
					    {% block content %}
 | 
				
			||||||
 | 
					    {% endblock %}
 | 
				
			||||||
 | 
					</main>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -12,4 +12,4 @@ class EventListView(PermissionListMixin, ListView):
 | 
				
			|||||||
    template_name = "administration/audit/list.html"
 | 
					    template_name = "administration/audit/list.html"
 | 
				
			||||||
    permission_required = "passbook_audit.view_event"
 | 
					    permission_required = "passbook_audit.view_event"
 | 
				
			||||||
    ordering = "-created"
 | 
					    ordering = "-created"
 | 
				
			||||||
    paginate_by = 10
 | 
					    paginate_by = 20
 | 
				
			||||||
 | 
				
			|||||||
@ -23,6 +23,8 @@ class InvitationListView(LoginRequiredMixin, PermissionListMixin, ListView):
 | 
				
			|||||||
    model = Invitation
 | 
					    model = Invitation
 | 
				
			||||||
    permission_required = "passbook_core.view_invitation"
 | 
					    permission_required = "passbook_core.view_invitation"
 | 
				
			||||||
    template_name = "administration/invitation/list.html"
 | 
					    template_name = "administration/invitation/list.html"
 | 
				
			||||||
 | 
					    paginate_by = 10
 | 
				
			||||||
 | 
					    ordering = "-expires"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InvitationCreateView(
 | 
					class InvitationCreateView(
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,7 @@ class PolicyListView(LoginRequiredMixin, PermissionListMixin, ListView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    model = Policy
 | 
					    model = Policy
 | 
				
			||||||
    permission_required = "passbook_core.view_policy"
 | 
					    permission_required = "passbook_core.view_policy"
 | 
				
			||||||
 | 
					    paginate_by = 10
 | 
				
			||||||
    ordering = "order"
 | 
					    ordering = "order"
 | 
				
			||||||
    template_name = "administration/policy/list.html"
 | 
					    template_name = "administration/policy/list.html"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ from rest_framework import routers
 | 
				
			|||||||
from structlog import get_logger
 | 
					from structlog import get_logger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from passbook.api.permissions import CustomObjectPermissions
 | 
					from passbook.api.permissions import CustomObjectPermissions
 | 
				
			||||||
from passbook.audit.api.events import EventViewSet
 | 
					from passbook.audit.api import EventViewSet
 | 
				
			||||||
from passbook.core.api.applications import ApplicationViewSet
 | 
					from passbook.core.api.applications import ApplicationViewSet
 | 
				
			||||||
from passbook.core.api.factors import FactorViewSet
 | 
					from passbook.core.api.factors import FactorViewSet
 | 
				
			||||||
from passbook.core.api.groups import GroupViewSet
 | 
					from passbook.core.api.groups import GroupViewSet
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ class EventSerializer(ModelSerializer):
 | 
				
			|||||||
            "date",
 | 
					            "date",
 | 
				
			||||||
            "app",
 | 
					            "app",
 | 
				
			||||||
            "context",
 | 
					            "context",
 | 
				
			||||||
            "request_ip",
 | 
					            "client_ip",
 | 
				
			||||||
            "created",
 | 
					            "created",
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -137,6 +137,7 @@ class Event(UUIDModel):
 | 
				
			|||||||
            action=self.action,
 | 
					            action=self.action,
 | 
				
			||||||
            context=self.context,
 | 
					            context=self.context,
 | 
				
			||||||
            client_ip=self.client_ip,
 | 
					            client_ip=self.client_ip,
 | 
				
			||||||
 | 
					            user=self.user,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return super().save(*args, **kwargs)
 | 
					        return super().save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,8 @@ class ApplicationForm(forms.ModelForm):
 | 
				
			|||||||
    """Application Form"""
 | 
					    """Application Form"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    provider = forms.ModelChoiceField(
 | 
					    provider = forms.ModelChoiceField(
 | 
				
			||||||
        queryset=Provider.objects.all().select_subclasses(), required=False
 | 
					        queryset=Provider.objects.all().order_by("pk").select_subclasses(),
 | 
				
			||||||
 | 
					        required=False,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										27
									
								
								passbook/core/templates/403_csrf.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								passbook/core/templates/403_csrf.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					{% extends 'login/base.html' %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% load static %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% load utils %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block card_title %}
 | 
				
			||||||
 | 
					{{ title }} <span>(403)</span>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block card %}
 | 
				
			||||||
 | 
					<form>
 | 
				
			||||||
 | 
					    <h3>{{ main }}</h3>
 | 
				
			||||||
 | 
					    {% if no_referer %}
 | 
				
			||||||
 | 
					    <p>{{ no_referer1 }}</p>
 | 
				
			||||||
 | 
					    <p>{{ no_referer2 }}</p>
 | 
				
			||||||
 | 
					    <p>{{ no_referer3 }}</p>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					    {% if no_cookie %}
 | 
				
			||||||
 | 
					    <p>{{ no_cookie1 }}</p>
 | 
				
			||||||
 | 
					    <p>{{ no_cookie2 }}</p>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					    {% if 'back' in request.GET %}
 | 
				
			||||||
 | 
					    <a href="{% back %}" class="btn btn-primary btn-block btn-lg">{% trans 'Back' %}</a>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										58
									
								
								passbook/core/templates/base/page.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								passbook/core/templates/base/page.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					{% extends "base/skeleton.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% load static %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% load is_active %}
 | 
				
			||||||
 | 
					{% load utils %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block body %}
 | 
				
			||||||
 | 
					{% include 'partials/messages.html' %}
 | 
				
			||||||
 | 
					<div class="pf-c-page" id="page-default-nav-example">
 | 
				
			||||||
 | 
					    <a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a>
 | 
				
			||||||
 | 
					    <header role="banner" class="pf-c-page__header ws-page-header">
 | 
				
			||||||
 | 
					        <div class="pf-c-page__header-brand">
 | 
				
			||||||
 | 
					            <div class="pf-c-page__header-brand-toggle">
 | 
				
			||||||
 | 
					                <button class="pf-c-button pf-m-plain" type="button" id="page-default-nav-example-nav-toggle"
 | 
				
			||||||
 | 
					                    aria-label="Global navigation" aria-expanded="true"
 | 
				
			||||||
 | 
					                    aria-controls="page-default-nav-example-primary-nav">
 | 
				
			||||||
 | 
					                    <i class="fas fa-bars" aria-hidden="true"></i>
 | 
				
			||||||
 | 
					                </button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <a class="pf-c-page__header-brand-link">
 | 
				
			||||||
 | 
					                <img class="pf-c-brand" src="{% static 'passbook/logo.png' %}" alt="" />
 | 
				
			||||||
 | 
					                <img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" alt="passbook" />
 | 
				
			||||||
 | 
					            </a>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="pf-c-page__header-nav">
 | 
				
			||||||
 | 
					            <nav class="pf-c-nav" aria-label="Nav">
 | 
				
			||||||
 | 
					                <ul class="pf-c-nav__horizontal-list ws-top-nav">
 | 
				
			||||||
 | 
					                    <li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_core:overview' %}"
 | 
				
			||||||
 | 
					                            href="{% url 'passbook_core:overview' %}">{% trans 'Access' %}</a></li>
 | 
				
			||||||
 | 
					                    {% if user.is_superuser %}
 | 
				
			||||||
 | 
					                    <li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_admin:overview' %}"
 | 
				
			||||||
 | 
					                            href="{% url 'passbook_admin:overview' %}">{% trans 'Administrate' %}</a></li>
 | 
				
			||||||
 | 
					                    <li class="pf-c-nav__item"><a class="pf-c-nav__link {% is_active_url 'passbook_admin:audit-log' %}"
 | 
				
			||||||
 | 
					                            href="{% url 'passbook_admin:audit-log' %}">{% trans 'Monitor' %}</a></li>
 | 
				
			||||||
 | 
					                    {% endif %}
 | 
				
			||||||
 | 
					                </ul>
 | 
				
			||||||
 | 
					            </nav>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="pf-c-page__header-tools">
 | 
				
			||||||
 | 
					            <div class="pf-c-page__header-tools-group pf-m-icons">
 | 
				
			||||||
 | 
					                <a href="{% url 'passbook_core:auth-logout' %}" class="pf-c-button pf-m-plain" type="button">
 | 
				
			||||||
 | 
					                    <i class="fas fa-sign-out-alt" aria-hidden="true"></i>
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="pf-c-page__header-tools-group">
 | 
				
			||||||
 | 
					                <a href="{% url 'passbook_core:user-settings' %}" class="pf-c-button">
 | 
				
			||||||
 | 
					                    {{ user.username }}
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <img class="pf-c-avatar" src="{% gravatar user.email %}" alt="">
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </header>
 | 
				
			||||||
 | 
					    {% block page_content %}
 | 
				
			||||||
 | 
					    {% endblock %}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@ -8,7 +8,7 @@
 | 
				
			|||||||
    <head>
 | 
					    <head>
 | 
				
			||||||
        <meta charset="UTF-8">
 | 
					        <meta charset="UTF-8">
 | 
				
			||||||
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
 | 
					        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
 | 
				
			||||||
        <title>{% block title %}{% title %}{% endblock %}</title>
 | 
					        <title>{% block title %}{% trans title %}{% endblock %}</title>
 | 
				
			||||||
        <link rel="icon" type="image/png" href="{% static 'passbook/logo.png' %}">
 | 
					        <link rel="icon" type="image/png" href="{% static 'passbook/logo.png' %}">
 | 
				
			||||||
        <link rel="shortcut icon" type="image/png" href="{% static 'passbook/logo.png' %}">
 | 
					        <link rel="shortcut icon" type="image/png" href="{% static 'passbook/logo.png' %}">
 | 
				
			||||||
        <link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly.css' %}">
 | 
					        <link rel="stylesheet" type="text/css" href="{% static 'node_modules/@patternfly/patternfly/patternfly.css' %}">
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,6 @@
 | 
				
			|||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
{% config 'passbook.branding' as branding %}
 | 
					 | 
				
			||||||
<!-- HERO -->
 | 
					<!-- HERO -->
 | 
				
			||||||
<tr>
 | 
					<tr>
 | 
				
			||||||
  <td bgcolor="#7c72dc" align="center" style="padding: 0px 10px 0px 10px;">
 | 
					  <td bgcolor="#7c72dc" align="center" style="padding: 0px 10px 0px 10px;">
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					<!DOCTYPE html>
 | 
				
			||||||
<html>
 | 
					<html>
 | 
				
			||||||
<head>
 | 
					<head>
 | 
				
			||||||
    <title>{% config passbook.branding %}</title>
 | 
					    <title>passbook</title>
 | 
				
			||||||
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 | 
					    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 | 
				
			||||||
    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
 | 
					    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
 | 
				
			||||||
@ -118,7 +118,7 @@
 | 
				
			|||||||
                        <!-- ADDRESS -->
 | 
					                        <!-- ADDRESS -->
 | 
				
			||||||
                        <tr>
 | 
					                        <tr>
 | 
				
			||||||
                            <td bgcolor="#1b2a32" align="left" style="padding: 0px 30px 30px 30px; color: #E9ECEF; font-family: 'Metropolis', Helvetica, Arial, sans-serif; font-size: 14px; font-weight: 400; line-height: 18px;">
 | 
					                            <td bgcolor="#1b2a32" align="left" style="padding: 0px 30px 30px 30px; color: #E9ECEF; font-family: 'Metropolis', Helvetica, Arial, sans-serif; font-size: 14px; font-weight: 400; line-height: 18px;">
 | 
				
			||||||
                                <p style="margin: 0;"><a href="{% config 'passbook.branding' %}">{% config 'passbook.branding' %}</a></p>
 | 
					                                <p style="margin: 0;"><a href="passbook">passbook</a></p>
 | 
				
			||||||
                            </td>
 | 
					                            </td>
 | 
				
			||||||
                        </tr>
 | 
					                        </tr>
 | 
				
			||||||
                    </table>
 | 
					                    </table>
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@
 | 
				
			|||||||
        <header class="pf-c-login__header">
 | 
					        <header class="pf-c-login__header">
 | 
				
			||||||
            <img class="pf-c-brand" src="{% static 'passbook/logo.svg' %}" style="height: 60px;"
 | 
					            <img class="pf-c-brand" src="{% static 'passbook/logo.svg' %}" style="height: 60px;"
 | 
				
			||||||
                alt="passbook icon" />
 | 
					                alt="passbook icon" />
 | 
				
			||||||
            <img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" style="height: 80px;"
 | 
					            <img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" style="height: 60px;"
 | 
				
			||||||
                alt="passbook branding" />
 | 
					                alt="passbook branding" />
 | 
				
			||||||
        </header>
 | 
					        </header>
 | 
				
			||||||
        <main class="pf-c-login__main">
 | 
					        <main class="pf-c-login__main">
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@
 | 
				
			|||||||
{% load utils %}
 | 
					{% load utils %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block title %}
 | 
					{% block title %}
 | 
				
			||||||
{% title title %}
 | 
					{% trans title %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block head %}
 | 
					{% block head %}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
{% extends "base/skeleton.html" %}
 | 
					{% extends "base/page.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% load static %}
 | 
					{% load static %}
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
@ -6,120 +6,10 @@
 | 
				
			|||||||
{% load is_active %}
 | 
					{% load is_active %}
 | 
				
			||||||
{% load utils %}
 | 
					{% load utils %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block body %}
 | 
					{% block page_content %}
 | 
				
			||||||
{% include 'partials/messages.html' %}
 | 
					{% include 'partials/messages.html' %}
 | 
				
			||||||
<div class="pf-c-page" id="page-default-nav-example">
 | 
					<main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
 | 
				
			||||||
    <a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a>
 | 
					    {% block content %}
 | 
				
			||||||
    <header role="banner" class="pf-c-page__header">
 | 
					    {% endblock %}
 | 
				
			||||||
        <div class="pf-c-page__header-brand">
 | 
					</main>
 | 
				
			||||||
            <div class="pf-c-page__header-brand-toggle">
 | 
					 | 
				
			||||||
                <button class="pf-c-button pf-m-plain" type="button" id="page-default-nav-example-nav-toggle"
 | 
					 | 
				
			||||||
                    aria-label="Global navigation" aria-expanded="true"
 | 
					 | 
				
			||||||
                    aria-controls="page-default-nav-example-primary-nav">
 | 
					 | 
				
			||||||
                    <i class="fas fa-bars" aria-hidden="true"></i>
 | 
					 | 
				
			||||||
                </button>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <a class="pf-c-page__header-brand-link">
 | 
					 | 
				
			||||||
                <img class="pf-c-brand" src="{% static 'passbook/logo.png' %}" alt="" />
 | 
					 | 
				
			||||||
                <img class="pf-c-brand" src="{% static 'passbook/brand.svg' %}" alt="passbook" />
 | 
					 | 
				
			||||||
            </a>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
        <div class="pf-c-page__header-tools">
 | 
					 | 
				
			||||||
            <div class="pf-c-page__header-tools-group pf-m-icons">
 | 
					 | 
				
			||||||
                <a href="{% url 'passbook_core:auth-logout' %}" class="pf-c-button pf-m-plain" type="button">
 | 
					 | 
				
			||||||
                    <i class="fas fa-sign-out-alt" aria-hidden="true"></i>
 | 
					 | 
				
			||||||
                </a>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <div class="pf-c-page__header-tools-group">
 | 
					 | 
				
			||||||
                <a href="{% url 'passbook_core:user-settings' %}" class="pf-c-button">
 | 
					 | 
				
			||||||
                    {{ user.username }}
 | 
					 | 
				
			||||||
                </a>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
            <img class="pf-c-avatar" src="{% gravatar user.email %}" alt="">
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </header>
 | 
					 | 
				
			||||||
    <div class="pf-c-page__sidebar pf-m-dark">
 | 
					 | 
				
			||||||
        <div class="pf-c-page__sidebar-body">
 | 
					 | 
				
			||||||
            <nav class="pf-c-nav pf-m-dark" id="page-default-nav-example-primary-nav" aria-label="Global">
 | 
					 | 
				
			||||||
                <ul class="pf-c-nav__list">
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_core:overview' %}" class="pf-c-nav__link  {% is_active_url 'passbook_core:overview' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Overview' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    {% if user.is_superuser %}
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:overview' %}" class="pf-c-nav__link {% is_active_url 'passbook_admin:overview' %}">
 | 
					 | 
				
			||||||
                            {% trans 'System Status' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:applications' %}" class="pf-c-nav__link {% is_active 'passbook_admin:applications' 'passbook_admin:application-create' 'passbook_admin:application-update' 'passbook_admin:application-delete' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Applications' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:sources' %}" class="pf-c-nav__link {% is_active 'passbook_admin:sources' 'passbook_admin:source-create' 'passbook_admin:source-update' 'passbook_admin:source-delete' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Sources' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:providers' %}" class="pf-c-nav__link {% is_active 'passbook_admin:providers' 'passbook_admin:provider-create' 'passbook_admin:provider-update' 'passbook_admin:provider-delete' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Providers' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:property-mappings' %}" class="pf-c-nav__link {% is_active 'passbook_admin:property-mappings' 'passbook_admin:property-mapping-create' 'passbook_admin:property-mapping-update' 'passbook_admin:property-mapping-delete' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Property Mappings' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:factors' %}" class="pf-c-nav__link {% is_active 'passbook_admin:factors' 'passbook_admin:factor-create' 'passbook_admin:factor-update' 'passbook_admin:factor-delete' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Factors' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:policies' %}" class="pf-c-nav__link {% is_active 'passbook_admin:policies' 'passbook_admin:policy-create' 'passbook_admin:policy-update' 'passbook_admin:policy-delete' 'passbook_admin:policy-test' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Policies' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:invitations' %}" class="pf-c-nav__link {% is_active 'passbook_admin:invitations' 'passbook_admin:invitation-create' 'passbook_admin:invitation-update' 'passbook_admin:invitation-delete' 'passbook_admin:invitation-test' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Invitations' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:users' %}" class="pf-c-nav__link {% is_active 'passbook_admin:users' 'passbook_admin:user-update' 'passbook_admin:user-delete' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Users' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:groups' %}" class="pf-c-nav__link {% is_active 'passbook_admin:groups' 'passbook_admin:group-update' 'passbook_admin:group-delete' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Groups' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    <li class="pf-c-nav__item">
 | 
					 | 
				
			||||||
                        <a href="{% url 'passbook_admin:audit-log' %}" class="pf-c-nav__link {% is_active 'passbook_admin:audit-log' %}">
 | 
					 | 
				
			||||||
                            {% trans 'Audit Log' %}
 | 
					 | 
				
			||||||
                        </a>
 | 
					 | 
				
			||||||
                    </li>
 | 
					 | 
				
			||||||
                    {% endif %}
 | 
					 | 
				
			||||||
                </ul>
 | 
					 | 
				
			||||||
            </nav>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
    </div>
 | 
					 | 
				
			||||||
    <main role="main" class="pf-c-page__main" tabindex="-1" id="main-content">
 | 
					 | 
				
			||||||
        {% block content %}
 | 
					 | 
				
			||||||
            <section class="pf-c-page__main-section pf-m-light">
 | 
					 | 
				
			||||||
                <div class="pf-c-content">
 | 
					 | 
				
			||||||
                    <h1>Main title</h1>
 | 
					 | 
				
			||||||
                    <p>This is a demo of the Page component.</p>
 | 
					 | 
				
			||||||
                </div>
 | 
					 | 
				
			||||||
            </section>
 | 
					 | 
				
			||||||
            <section class="pf-c-page__main-section">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            </section>
 | 
					 | 
				
			||||||
        {% endblock %}
 | 
					 | 
				
			||||||
    </main>
 | 
					 | 
				
			||||||
</div>
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -231,7 +231,6 @@ class PasswordResetView(View):
 | 
				
			|||||||
        login(request, nonce.user)
 | 
					        login(request, nonce.user)
 | 
				
			||||||
        nonce.delete()
 | 
					        nonce.delete()
 | 
				
			||||||
        messages.success(
 | 
					        messages.success(
 | 
				
			||||||
            request,
 | 
					            request, _(("Temporarily authenticated, please change your password")),
 | 
				
			||||||
            _(("Temporarily authenticated with Nonce, " "please change your password")),
 | 
					 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        return redirect("passbook_core:user-change-password")
 | 
					        return redirect("passbook_core:user-change-password")
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
from captcha.fields import ReCaptchaField
 | 
					from captcha.fields import ReCaptchaField
 | 
				
			||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
					from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
				
			||||||
from django.utils.translation import gettext as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from passbook.factors.captcha.models import CaptchaFactor
 | 
					from passbook.factors.captcha.models import CaptchaFactor
 | 
				
			||||||
from passbook.factors.forms import GENERAL_FIELDS
 | 
					from passbook.factors.forms import GENERAL_FIELDS
 | 
				
			||||||
@ -28,3 +28,8 @@ class CaptchaFactorForm(forms.ModelForm):
 | 
				
			|||||||
            "public_key": forms.TextInput(),
 | 
					            "public_key": forms.TextInput(),
 | 
				
			||||||
            "private_key": forms.TextInput(),
 | 
					            "private_key": forms.TextInput(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        help_texts = {
 | 
				
			||||||
 | 
					            "policies": _(
 | 
				
			||||||
 | 
					                "Policies which determine if this factor applies to the current user."
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
"""passbook administration forms"""
 | 
					"""passbook administration forms"""
 | 
				
			||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
					from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
				
			||||||
from django.utils.translation import gettext as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from passbook.factors.email.models import EmailFactor
 | 
					from passbook.factors.email.models import EmailFactor
 | 
				
			||||||
from passbook.factors.forms import GENERAL_FIELDS
 | 
					from passbook.factors.forms import GENERAL_FIELDS
 | 
				
			||||||
@ -41,3 +41,8 @@ class EmailFactorForm(forms.ModelForm):
 | 
				
			|||||||
            "ssl_keyfile": _("SSL Keyfile (optional)"),
 | 
					            "ssl_keyfile": _("SSL Keyfile (optional)"),
 | 
				
			||||||
            "ssl_certfile": _("SSL Certfile (optional)"),
 | 
					            "ssl_certfile": _("SSL Certfile (optional)"),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        help_texts = {
 | 
				
			||||||
 | 
					            "policies": _(
 | 
				
			||||||
 | 
					                "Policies which determine if this factor applies to the current user."
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ from django import forms
 | 
				
			|||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
					from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
				
			||||||
from django.core.validators import RegexValidator
 | 
					from django.core.validators import RegexValidator
 | 
				
			||||||
from django.utils.safestring import mark_safe
 | 
					from django.utils.safestring import mark_safe
 | 
				
			||||||
from django.utils.translation import ugettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from django_otp.models import Device
 | 
					from django_otp.models import Device
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from passbook.factors.forms import GENERAL_FIELDS
 | 
					from passbook.factors.forms import GENERAL_FIELDS
 | 
				
			||||||
@ -80,3 +80,8 @@ class OTPFactorForm(forms.ModelForm):
 | 
				
			|||||||
            "order": forms.NumberInput(),
 | 
					            "order": forms.NumberInput(),
 | 
				
			||||||
            "policies": FilteredSelectMultiple(_("policies"), False),
 | 
					            "policies": FilteredSelectMultiple(_("policies"), False),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        help_texts = {
 | 
				
			||||||
 | 
					            "policies": _(
 | 
				
			||||||
 | 
					                "Policies which determine if this factor applies to the current user."
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
from django import forms
 | 
					from django import forms
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
					from django.contrib.admin.widgets import FilteredSelectMultiple
 | 
				
			||||||
from django.utils.translation import gettext as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from passbook.factors.forms import GENERAL_FIELDS
 | 
					from passbook.factors.forms import GENERAL_FIELDS
 | 
				
			||||||
from passbook.factors.password.models import PasswordFactor
 | 
					from passbook.factors.password.models import PasswordFactor
 | 
				
			||||||
@ -49,3 +49,8 @@ class PasswordFactorForm(forms.ModelForm):
 | 
				
			|||||||
            "password_policies": FilteredSelectMultiple(_("password policies"), False),
 | 
					            "password_policies": FilteredSelectMultiple(_("password policies"), False),
 | 
				
			||||||
            "reset_factors": FilteredSelectMultiple(_("reset factors"), False),
 | 
					            "reset_factors": FilteredSelectMultiple(_("reset factors"), False),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        help_texts = {
 | 
				
			||||||
 | 
					            "policies": _(
 | 
				
			||||||
 | 
					                "Policies which determine if this factor applies to the current user."
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -25,18 +25,6 @@ passbook:
 | 
				
			|||||||
  password_reset:
 | 
					  password_reset:
 | 
				
			||||||
    # Enable password reset, passwords are reset in internal Database and in LDAP if ldap.reset_password is true
 | 
					    # Enable password reset, passwords are reset in internal Database and in LDAP if ldap.reset_password is true
 | 
				
			||||||
    enabled: true
 | 
					    enabled: true
 | 
				
			||||||
    # Verification the user has to provide in order to be able to reset passwords. Can be any combination of `email`, `2fa`, `security_questions`
 | 
					 | 
				
			||||||
    verification:
 | 
					 | 
				
			||||||
      - email
 | 
					 | 
				
			||||||
  # Text used in title, on login page and multiple other places
 | 
					 | 
				
			||||||
  branding: passbook
 | 
					 | 
				
			||||||
  login:
 | 
					 | 
				
			||||||
    # Override URL used for logo
 | 
					 | 
				
			||||||
    logo_url: null
 | 
					 | 
				
			||||||
    # Override URL used for Background on Login page
 | 
					 | 
				
			||||||
    bg_url: null
 | 
					 | 
				
			||||||
    # Optionally add a subtext, placed below logo on the login page
 | 
					 | 
				
			||||||
    subtext: null
 | 
					 | 
				
			||||||
  footer:
 | 
					  footer:
 | 
				
			||||||
    links:
 | 
					    links:
 | 
				
			||||||
      # Optionally add links to the footer on the login page
 | 
					      # Optionally add links to the footer on the login page
 | 
				
			||||||
@ -46,14 +34,3 @@ passbook:
 | 
				
			|||||||
  uid_fields:
 | 
					  uid_fields:
 | 
				
			||||||
    - username
 | 
					    - username
 | 
				
			||||||
    - email
 | 
					    - email
 | 
				
			||||||
# Provider-specific settings
 | 
					 | 
				
			||||||
ldap:
 | 
					 | 
				
			||||||
  # Which field from `uid_fields` maps to which LDAP Attribute
 | 
					 | 
				
			||||||
  login_field_map:
 | 
					 | 
				
			||||||
    username: sAMAccountName
 | 
					 | 
				
			||||||
    email: mail # or userPrincipalName
 | 
					 | 
				
			||||||
  user_attribute_map:
 | 
					 | 
				
			||||||
    active_directory:
 | 
					 | 
				
			||||||
      username: "%(sAMAccountName)s"
 | 
					 | 
				
			||||||
      email: "%(mail)s"
 | 
					 | 
				
			||||||
      name: "%(displayName)"
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -5,5 +5,5 @@ from os import getpid
 | 
				
			|||||||
# pylint: disable=unused-argument
 | 
					# pylint: disable=unused-argument
 | 
				
			||||||
def add_process_id(logger, method_name, event_dict):
 | 
					def add_process_id(logger, method_name, event_dict):
 | 
				
			||||||
    """Add the current process ID"""
 | 
					    """Add the current process ID"""
 | 
				
			||||||
    event_dict["pdi"] = getpid()
 | 
					    event_dict["pid"] = getpid()
 | 
				
			||||||
    return event_dict
 | 
					    return event_dict
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ LOGGER = get_logger()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SentryIgnoredException(Exception):
 | 
					class SentryIgnoredException(Exception):
 | 
				
			||||||
    """Base Class for all errors that are supressed, and not sent to sentry."""
 | 
					    """Base Class for all errors that are suppressed, and not sent to sentry."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def before_send(event, hint):
 | 
					def before_send(event, hint):
 | 
				
			||||||
 | 
				
			|||||||
@ -3,11 +3,9 @@ from hashlib import md5
 | 
				
			|||||||
from urllib.parse import urlencode
 | 
					from urllib.parse import urlencode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django import template
 | 
					from django import template
 | 
				
			||||||
from django.apps import apps
 | 
					 | 
				
			||||||
from django.db.models import Model
 | 
					from django.db.models import Model
 | 
				
			||||||
from django.template import Context
 | 
					from django.template import Context
 | 
				
			||||||
from django.utils.html import escape
 | 
					from django.utils.html import escape
 | 
				
			||||||
from django.utils.translation import ugettext as _
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from passbook.lib.config import CONFIG
 | 
					from passbook.lib.config import CONFIG
 | 
				
			||||||
from passbook.lib.utils.urls import is_url_absolute
 | 
					from passbook.lib.utils.urls import is_url_absolute
 | 
				
			||||||
@ -40,38 +38,6 @@ def fieldtype(field):
 | 
				
			|||||||
    return field.__class__.__name__
 | 
					    return field.__class__.__name__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@register.simple_tag(takes_context=True)
 | 
					 | 
				
			||||||
def title(context: Context, *title) -> str:
 | 
					 | 
				
			||||||
    """Return either just branding or title - branding"""
 | 
					 | 
				
			||||||
    branding = CONFIG.y("passbook.branding", "passbook")
 | 
					 | 
				
			||||||
    if not title:
 | 
					 | 
				
			||||||
        return branding
 | 
					 | 
				
			||||||
    if "request" not in context:
 | 
					 | 
				
			||||||
        return ""
 | 
					 | 
				
			||||||
    resolver_match = context.request.resolver_match
 | 
					 | 
				
			||||||
    if not resolver_match:
 | 
					 | 
				
			||||||
        return ""
 | 
					 | 
				
			||||||
    # Include App Title in title
 | 
					 | 
				
			||||||
    app = ""
 | 
					 | 
				
			||||||
    if resolver_match.namespace != "":
 | 
					 | 
				
			||||||
        dj_app = None
 | 
					 | 
				
			||||||
        namespace = context.request.resolver_match.namespace.split(":")[0]
 | 
					 | 
				
			||||||
        # New label (App URL Namespace == App Label)
 | 
					 | 
				
			||||||
        dj_app = apps.get_app_config(namespace)
 | 
					 | 
				
			||||||
        title_modifier = getattr(dj_app, "title_modifier", None)
 | 
					 | 
				
			||||||
        if title_modifier:
 | 
					 | 
				
			||||||
            app_title = dj_app.title_modifier(context.request)
 | 
					 | 
				
			||||||
            app = app_title + " -"
 | 
					 | 
				
			||||||
    return _(
 | 
					 | 
				
			||||||
        "%(title)s - %(app)s %(branding)s"
 | 
					 | 
				
			||||||
        % {
 | 
					 | 
				
			||||||
            "title": " - ".join([str(x) for x in title]),
 | 
					 | 
				
			||||||
            "branding": branding,
 | 
					 | 
				
			||||||
            "app": app,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@register.simple_tag
 | 
					@register.simple_tag
 | 
				
			||||||
def config(path, default=""):
 | 
					def config(path, default=""):
 | 
				
			||||||
    """Get a setting from the database. Returns default is setting doesn't exist."""
 | 
					    """Get a setting from the database. Returns default is setting doesn't exist."""
 | 
				
			||||||
 | 
				
			|||||||
@ -34,7 +34,7 @@ class ApplicationGatewayProviderSerializer(ModelSerializer):
 | 
				
			|||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        model = ApplicationGatewayProvider
 | 
					        model = ApplicationGatewayProvider
 | 
				
			||||||
        fields = ["pk", "name", "host", "client"]
 | 
					        fields = ["pk", "name", "internal_host", "external_host", "client"]
 | 
				
			||||||
        read_only_fields = ["client"]
 | 
					        read_only_fields = ["client"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block card_title %}
 | 
					{% block card_title %}
 | 
				
			||||||
{% title 'Authorize Application' %}
 | 
					{% trans 'Authorize Application' %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block card %}
 | 
					{% block card %}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										18
									
								
								passbook/providers/oidc/templates/oidc_provider/error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								passbook/providers/oidc/templates/oidc_provider/error.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					{% extends 'login/base.html' %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% load static %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% load utils %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block card_title %}
 | 
				
			||||||
 | 
					{% trans error %}
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block card %}
 | 
				
			||||||
 | 
					<form>
 | 
				
			||||||
 | 
					    <h3>{% trans description %}</h3>
 | 
				
			||||||
 | 
					    {% if 'back' in request.GET %}
 | 
				
			||||||
 | 
					    <a href="{% back %}" class="btn btn-primary btn-block btn-lg">{% trans 'Back' %}</a>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@ -184,7 +184,7 @@ class Processor:
 | 
				
			|||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self._extract_saml_request()
 | 
					            self._extract_saml_request()
 | 
				
			||||||
        except KeyError:
 | 
					        except KeyError:
 | 
				
			||||||
            raise CannotHandleAssertion(f"Couldn't find SAML request in user session:")
 | 
					            raise CannotHandleAssertion(f"Couldn't find SAML request in user session")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self._decode_and_parse_request()
 | 
					            self._decode_and_parse_request()
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block card_title %}
 | 
					{% block card_title %}
 | 
				
			||||||
{% title 'Redirecting...' %}
 | 
					{% trans 'Redirecting...' %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block card %}
 | 
					{% block card %}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,11 +4,8 @@
 | 
				
			|||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block card %}
 | 
					{% block card %}
 | 
				
			||||||
<form method="POST" class="pf-c-form" action="{{ saml_params.acs_url }}">
 | 
					<form method="POST" class="pf-c-form">
 | 
				
			||||||
    {% csrf_token %}
 | 
					    {% csrf_token %}
 | 
				
			||||||
    <input type="hidden" name="ACSUrl" value="{{ saml_params.acs_url }}">
 | 
					 | 
				
			||||||
    <input type="hidden" name="RelayState" value="{{ saml_params.relay_state }}" />
 | 
					 | 
				
			||||||
    <input type="hidden" name="SAMLResponse" value="{{ saml_params.saml_response }}" />
 | 
					 | 
				
			||||||
    <div class="pf-c-form__group">
 | 
					    <div class="pf-c-form__group">
 | 
				
			||||||
        <h3>
 | 
					        <h3>
 | 
				
			||||||
            {% blocktrans with provider=provider.application.name %}
 | 
					            {% blocktrans with provider=provider.application.name %}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,9 +16,9 @@ urlpatterns = [
 | 
				
			|||||||
        "<slug:application>/login/", views.LoginBeginView.as_view(), name="saml-login"
 | 
					        "<slug:application>/login/", views.LoginBeginView.as_view(), name="saml-login"
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    path(
 | 
					    path(
 | 
				
			||||||
        "<slug:application>/login/process/",
 | 
					        "<slug:application>/login/authorize/",
 | 
				
			||||||
        views.LoginProcessView.as_view(),
 | 
					        views.AuthorizeView.as_view(),
 | 
				
			||||||
        name="saml-login-process",
 | 
					        name="saml-login-authorize",
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    path("<slug:application>/logout/", views.LogoutView.as_view(), name="saml-logout"),
 | 
					    path("<slug:application>/logout/", views.LogoutView.as_view(), name="saml-logout"),
 | 
				
			||||||
    path(
 | 
					    path(
 | 
				
			||||||
 | 
				
			|||||||
@ -21,12 +21,16 @@ from passbook.core.models import Application, Provider
 | 
				
			|||||||
from passbook.lib.utils.template import render_to_string
 | 
					from passbook.lib.utils.template import render_to_string
 | 
				
			||||||
from passbook.lib.views import bad_request_message
 | 
					from passbook.lib.views import bad_request_message
 | 
				
			||||||
from passbook.policies.engine import PolicyEngine
 | 
					from passbook.policies.engine import PolicyEngine
 | 
				
			||||||
from passbook.providers.saml import exceptions
 | 
					from passbook.providers.saml.exceptions import CannotHandleAssertion
 | 
				
			||||||
from passbook.providers.saml.models import SAMLProvider
 | 
					from passbook.providers.saml.models import SAMLProvider
 | 
				
			||||||
from passbook.providers.saml.processors.types import SAMLResponseParams
 | 
					from passbook.providers.saml.processors.types import SAMLResponseParams
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOGGER = get_logger()
 | 
					LOGGER = get_logger()
 | 
				
			||||||
URL_VALIDATOR = URLValidator(schemes=("http", "https"))
 | 
					URL_VALIDATOR = URLValidator(schemes=("http", "https"))
 | 
				
			||||||
 | 
					SESSION_KEY_SAML_REQUEST = "SAMLRequest"
 | 
				
			||||||
 | 
					SESSION_KEY_SAML_RESPONSE = "SAMLResponse"
 | 
				
			||||||
 | 
					SESSION_KEY_RELAY_STATE = "RelayState"
 | 
				
			||||||
 | 
					SESSION_KEY_PARAMS = "SAMLParams"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AccessRequiredView(AccessMixin, View):
 | 
					class AccessRequiredView(AccessMixin, View):
 | 
				
			||||||
@ -50,14 +54,18 @@ class AccessRequiredView(AccessMixin, View):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def _has_access(self) -> bool:
 | 
					    def _has_access(self) -> bool:
 | 
				
			||||||
        """Check if user has access to application"""
 | 
					        """Check if user has access to application"""
 | 
				
			||||||
        LOGGER.debug(
 | 
					 | 
				
			||||||
            "_has_access", user=self.request.user, app=self.provider.application
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        policy_engine = PolicyEngine(
 | 
					        policy_engine = PolicyEngine(
 | 
				
			||||||
            self.provider.application.policies.all(), self.request.user, self.request
 | 
					            self.provider.application.policies.all(), self.request.user, self.request
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        policy_engine.build()
 | 
					        policy_engine.build()
 | 
				
			||||||
        return policy_engine.passing
 | 
					        passing = policy_engine.passing
 | 
				
			||||||
 | 
					        LOGGER.debug(
 | 
				
			||||||
 | 
					            "saml_has_access",
 | 
				
			||||||
 | 
					            user=self.request.user,
 | 
				
			||||||
 | 
					            app=self.provider.application,
 | 
				
			||||||
 | 
					            passing=passing,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return passing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def dispatch(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
 | 
					    def dispatch(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
 | 
				
			||||||
        if not request.user.is_authenticated:
 | 
					        if not request.user.is_authenticated:
 | 
				
			||||||
@ -75,80 +83,29 @@ class LoginBeginView(AccessRequiredView):
 | 
				
			|||||||
    """Receives a SAML 2.0 AuthnRequest from a Service Provider and
 | 
					    """Receives a SAML 2.0 AuthnRequest from a Service Provider and
 | 
				
			||||||
    stores it in the session prior to enforcing login."""
 | 
					    stores it in the session prior to enforcing login."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @method_decorator(csrf_exempt)
 | 
					    def handler(self, source, application: str) -> HttpResponse:
 | 
				
			||||||
    def dispatch(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
					        """Handle SAML Request whether its a POST or a Redirect binding"""
 | 
				
			||||||
        if request.method == "POST":
 | 
					 | 
				
			||||||
            source = request.POST
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            source = request.GET
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Store these values now, because Django's login cycle won't preserve them.
 | 
					        # Store these values now, because Django's login cycle won't preserve them.
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            request.session["SAMLRequest"] = source["SAMLRequest"]
 | 
					            self.request.session[SESSION_KEY_SAML_REQUEST] = source[
 | 
				
			||||||
 | 
					                SESSION_KEY_SAML_REQUEST
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
        except (KeyError, MultiValueDictKeyError):
 | 
					        except (KeyError, MultiValueDictKeyError):
 | 
				
			||||||
            return bad_request_message(request, "The SAML request payload is missing.")
 | 
					            return bad_request_message(
 | 
				
			||||||
 | 
					                self.request, "The SAML request payload is missing."
 | 
				
			||||||
        request.session["RelayState"] = source.get("RelayState", "")
 | 
					 | 
				
			||||||
        return redirect(
 | 
					 | 
				
			||||||
            reverse(
 | 
					 | 
				
			||||||
                "passbook_providers_saml:saml-login-process",
 | 
					 | 
				
			||||||
                kwargs={"application": application},
 | 
					 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.request.session[SESSION_KEY_RELAY_STATE] = source.get(
 | 
				
			||||||
 | 
					            SESSION_KEY_RELAY_STATE, ""
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class LoginProcessView(AccessRequiredView):
 | 
					 | 
				
			||||||
    """Processor-based login continuation.
 | 
					 | 
				
			||||||
    Presents a SAML 2.0 Assertion for POSTing back to the Service Provider."""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def handle_redirect(
 | 
					 | 
				
			||||||
        self, params: SAMLResponseParams, skipped_authorization: bool
 | 
					 | 
				
			||||||
    ) -> HttpResponse:
 | 
					 | 
				
			||||||
        """Handle direct redirect to SP"""
 | 
					 | 
				
			||||||
        # Log Application Authorization
 | 
					 | 
				
			||||||
        Event.new(
 | 
					 | 
				
			||||||
            EventAction.AUTHORIZE_APPLICATION,
 | 
					 | 
				
			||||||
            authorized_application=self.provider.application,
 | 
					 | 
				
			||||||
            skipped_authorization=skipped_authorization,
 | 
					 | 
				
			||||||
        ).from_http(self.request)
 | 
					 | 
				
			||||||
        return render(
 | 
					 | 
				
			||||||
            self.request,
 | 
					 | 
				
			||||||
            "saml/idp/autosubmit_form.html",
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                "url": params.acs_url,
 | 
					 | 
				
			||||||
                "attrs": {
 | 
					 | 
				
			||||||
                    "SAMLResponse": params.saml_response,
 | 
					 | 
				
			||||||
                    "RelayState": params.relay_state,
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
					 | 
				
			||||||
        """Handle get request, i.e. render form"""
 | 
					 | 
				
			||||||
        # User access gets checked in dispatch
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Otherwise we generate the IdP initiated session
 | 
					 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            # application.skip_authorization is set so we directly redirect the user
 | 
					            self.provider.processor.can_handle(self.request)
 | 
				
			||||||
            if self.provider.application.skip_authorization:
 | 
					 | 
				
			||||||
                return self.post(request, application)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.provider.processor.init_deep_link(request)
 | 
					 | 
				
			||||||
            params = self.provider.processor.generate_response()
 | 
					            params = self.provider.processor.generate_response()
 | 
				
			||||||
 | 
					            self.request.session[SESSION_KEY_PARAMS] = params
 | 
				
			||||||
            return render(
 | 
					        except CannotHandleAssertion as exc:
 | 
				
			||||||
                request,
 | 
					            LOGGER.info(exc)
 | 
				
			||||||
                "saml/idp/login.html",
 | 
					            did_you_mean_link = self.request.build_absolute_uri(
 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    "saml_params": params,
 | 
					 | 
				
			||||||
                    "provider": self.provider,
 | 
					 | 
				
			||||||
                    "title": "Authorize Application",
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        except exceptions.CannotHandleAssertion as exc:
 | 
					 | 
				
			||||||
            LOGGER.error(exc)
 | 
					 | 
				
			||||||
            did_you_mean_link = request.build_absolute_uri(
 | 
					 | 
				
			||||||
                reverse(
 | 
					                reverse(
 | 
				
			||||||
                    "passbook_providers_saml:saml-login-initiate",
 | 
					                    "passbook_providers_saml:saml-login-initiate",
 | 
				
			||||||
                    kwargs={"application": application},
 | 
					                    kwargs={"application": application},
 | 
				
			||||||
@ -158,19 +115,101 @@ class LoginProcessView(AccessRequiredView):
 | 
				
			|||||||
                f" Did you mean to go <a href='{did_you_mean_link}'>here</a>?"
 | 
					                f" Did you mean to go <a href='{did_you_mean_link}'>here</a>?"
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            return bad_request_message(
 | 
					            return bad_request_message(
 | 
				
			||||||
                request, mark_safe(str(exc) + did_you_mean_message)
 | 
					                self.request, mark_safe(str(exc) + did_you_mean_message)
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return redirect(
 | 
				
			||||||
 | 
					            reverse(
 | 
				
			||||||
 | 
					                "passbook_providers_saml:saml-login-authorize",
 | 
				
			||||||
 | 
					                kwargs={"application": application},
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @method_decorator(csrf_exempt)
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super().dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @method_decorator(csrf_exempt)
 | 
				
			||||||
 | 
					    def get(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
				
			||||||
 | 
					        """Handle REDIRECT bindings"""
 | 
				
			||||||
 | 
					        return self.handler(request.GET, application)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @method_decorator(csrf_exempt)
 | 
				
			||||||
 | 
					    def post(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
				
			||||||
 | 
					        """Handle POST Bindings"""
 | 
				
			||||||
 | 
					        return self.handler(request.POST, application)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InitiateLoginView(AccessRequiredView):
 | 
				
			||||||
 | 
					    """IdP-initiated Login"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
				
			||||||
 | 
					        """Initiates an IdP-initiated link to a simple SP resource/target URL."""
 | 
				
			||||||
 | 
					        self.provider.processor.is_idp_initiated = True
 | 
				
			||||||
 | 
					        self.provider.processor.init_deep_link(request)
 | 
				
			||||||
 | 
					        params = self.provider.processor.generate_response()
 | 
				
			||||||
 | 
					        request.session[SESSION_KEY_PARAMS] = params
 | 
				
			||||||
 | 
					        return redirect(
 | 
				
			||||||
 | 
					            reverse(
 | 
				
			||||||
 | 
					                "passbook_providers_saml:saml-login-authorize",
 | 
				
			||||||
 | 
					                kwargs={"application": application},
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AuthorizeView(AccessRequiredView):
 | 
				
			||||||
 | 
					    """Ask the user for authorization to continue to the SP.
 | 
				
			||||||
 | 
					    Presents a SAML 2.0 Assertion for POSTing back to the Service Provider."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
				
			||||||
 | 
					        """Handle get request, i.e. render form"""
 | 
				
			||||||
 | 
					        # User access gets checked in dispatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Otherwise we generate the IdP initiated session
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            # application.skip_authorization is set so we directly redirect the user
 | 
				
			||||||
 | 
					            if self.provider.application.skip_authorization:
 | 
				
			||||||
 | 
					                LOGGER.debug("skipping authz", application=self.provider.application)
 | 
				
			||||||
 | 
					                return self.post(request, application)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return render(
 | 
				
			||||||
 | 
					                request,
 | 
				
			||||||
 | 
					                "saml/idp/login.html",
 | 
				
			||||||
 | 
					                {"provider": self.provider, "title": "Authorize Application",},
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            return bad_request_message(request, "Missing SAML Payload")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # pylint: disable=unused-argument
 | 
					    # pylint: disable=unused-argument
 | 
				
			||||||
    def post(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
					    def post(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
				
			||||||
        """Handle post request, return back to ACS"""
 | 
					        """Handle post request, return back to ACS"""
 | 
				
			||||||
        # User access gets checked in dispatch
 | 
					        # User access gets checked in dispatch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # we get here when skip_authorization is False, and after the user accepted
 | 
					        # we get here when skip_authorization is True, and after the user accepted
 | 
				
			||||||
        # the authorization form
 | 
					        # the authorization form
 | 
				
			||||||
        self.provider.processor.can_handle(request)
 | 
					        # Log Application Authorization
 | 
				
			||||||
        saml_params = self.provider.processor.generate_response()
 | 
					        Event.new(
 | 
				
			||||||
        return self.handle_redirect(saml_params, True)
 | 
					            EventAction.AUTHORIZE_APPLICATION,
 | 
				
			||||||
 | 
					            authorized_application=self.provider.application,
 | 
				
			||||||
 | 
					            skipped_authorization=self.provider.application.skip_authorization,
 | 
				
			||||||
 | 
					        ).from_http(self.request)
 | 
				
			||||||
 | 
					        self.request.session.pop(SESSION_KEY_SAML_REQUEST, None)
 | 
				
			||||||
 | 
					        self.request.session.pop(SESSION_KEY_SAML_RESPONSE, None)
 | 
				
			||||||
 | 
					        self.request.session.pop(SESSION_KEY_RELAY_STATE, None)
 | 
				
			||||||
 | 
					        response: SAMLResponseParams = self.request.session.pop(SESSION_KEY_PARAMS)
 | 
				
			||||||
 | 
					        return render(
 | 
				
			||||||
 | 
					            self.request,
 | 
				
			||||||
 | 
					            "saml/idp/autosubmit_form.html",
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                "url": response.acs_url,
 | 
				
			||||||
 | 
					                "attrs": {
 | 
				
			||||||
 | 
					                    "ACSUrl": response.acs_url,
 | 
				
			||||||
 | 
					                    SESSION_KEY_SAML_RESPONSE: response.saml_response,
 | 
				
			||||||
 | 
					                    SESSION_KEY_RELAY_STATE: response.relay_state,
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@method_decorator(csrf_exempt, name="dispatch")
 | 
					@method_decorator(csrf_exempt, name="dispatch")
 | 
				
			||||||
@ -204,7 +243,9 @@ class SLOLogout(AccessRequiredView):
 | 
				
			|||||||
    # pylint: disable=unused-argument
 | 
					    # pylint: disable=unused-argument
 | 
				
			||||||
    def post(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
					    def post(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
				
			||||||
        """Perform logout"""
 | 
					        """Perform logout"""
 | 
				
			||||||
        request.session["SAMLRequest"] = request.POST["SAMLRequest"]
 | 
					        request.session[SESSION_KEY_SAML_REQUEST] = request.POST[
 | 
				
			||||||
 | 
					            SESSION_KEY_SAML_REQUEST
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
        # TODO: Parse SAML LogoutRequest from POST data, similar to login_process().
 | 
					        # TODO: Parse SAML LogoutRequest from POST data, similar to login_process().
 | 
				
			||||||
        # TODO: Modify the base processor to handle logouts?
 | 
					        # TODO: Modify the base processor to handle logouts?
 | 
				
			||||||
        # TODO: Combine this with login_process(), since they are so very similar?
 | 
					        # TODO: Combine this with login_process(), since they are so very similar?
 | 
				
			||||||
@ -259,54 +300,7 @@ class DescriptorDownloadView(AccessRequiredView):
 | 
				
			|||||||
            )
 | 
					            )
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            response = HttpResponse(metadata, content_type="application/xml")
 | 
					            response = HttpResponse(metadata, content_type="application/xml")
 | 
				
			||||||
            response["Content-Disposition"] = (
 | 
					            response[
 | 
				
			||||||
                'attachment; filename="' '%s_passbook_meta.xml"' % self.provider.name
 | 
					                "Content-Disposition"
 | 
				
			||||||
            )
 | 
					            ] = f'attachment; filename="{self.provider.name}_passbook_meta.xml"'
 | 
				
			||||||
            return response
 | 
					            return response
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class InitiateLoginView(AccessRequiredView):
 | 
					 | 
				
			||||||
    """IdP-initiated Login"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def handle_redirect(
 | 
					 | 
				
			||||||
        self, params: SAMLResponseParams, skipped_authorization: bool
 | 
					 | 
				
			||||||
    ) -> HttpResponse:
 | 
					 | 
				
			||||||
        """Handle direct redirect to SP"""
 | 
					 | 
				
			||||||
        # Log Application Authorization
 | 
					 | 
				
			||||||
        Event.new(
 | 
					 | 
				
			||||||
            EventAction.AUTHORIZE_APPLICATION,
 | 
					 | 
				
			||||||
            authorized_application=self.provider.application,
 | 
					 | 
				
			||||||
            skipped_authorization=skipped_authorization,
 | 
					 | 
				
			||||||
        ).from_http(self.request)
 | 
					 | 
				
			||||||
        return render(
 | 
					 | 
				
			||||||
            self.request,
 | 
					 | 
				
			||||||
            "saml/idp/autosubmit_form.html",
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                "url": params.acs_url,
 | 
					 | 
				
			||||||
                "attrs": {
 | 
					 | 
				
			||||||
                    "SAMLResponse": params.saml_response,
 | 
					 | 
				
			||||||
                    "RelayState": params.relay_state,
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # pylint: disable=unused-argument
 | 
					 | 
				
			||||||
    def get(self, request: HttpRequest, application: str) -> HttpResponse:
 | 
					 | 
				
			||||||
        """Initiates an IdP-initiated link to a simple SP resource/target URL."""
 | 
					 | 
				
			||||||
        self.provider.processor.is_idp_initiated = True
 | 
					 | 
				
			||||||
        self.provider.processor.init_deep_link(request)
 | 
					 | 
				
			||||||
        params = self.provider.processor.generate_response()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # IdP-initiated Login Flow
 | 
					 | 
				
			||||||
        if self.provider.application.skip_authorization:
 | 
					 | 
				
			||||||
            return self.handle_redirect(params, True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return render(
 | 
					 | 
				
			||||||
            request,
 | 
					 | 
				
			||||||
            "saml/idp/login.html",
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                "saml_params": params,
 | 
					 | 
				
			||||||
                "provider": self.provider,
 | 
					 | 
				
			||||||
                "title": "Authorize Application",
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -317,7 +317,7 @@ LOGGING = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "handlers": {
 | 
					    "handlers": {
 | 
				
			||||||
        "console": {
 | 
					        "console": {
 | 
				
			||||||
            "level": DEBUG,
 | 
					            "level": "DEBUG",
 | 
				
			||||||
            "class": "logging.StreamHandler",
 | 
					            "class": "logging.StreamHandler",
 | 
				
			||||||
            "formatter": "colored" if DEBUG else "plain",
 | 
					            "formatter": "colored" if DEBUG else "plain",
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -325,6 +325,7 @@ LOGGING = {
 | 
				
			|||||||
    "loggers": {},
 | 
					    "loggers": {},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
_LOGGING_HANDLER_MAP = {
 | 
					_LOGGING_HANDLER_MAP = {
 | 
				
			||||||
 | 
					    "": "DEBUG",
 | 
				
			||||||
    "passbook": "DEBUG",
 | 
					    "passbook": "DEBUG",
 | 
				
			||||||
    "django": "WARNING",
 | 
					    "django": "WARNING",
 | 
				
			||||||
    "celery": "WARNING",
 | 
					    "celery": "WARNING",
 | 
				
			||||||
@ -337,7 +338,7 @@ for handler_name, level in _LOGGING_HANDLER_MAP.items():
 | 
				
			|||||||
    LOGGING["loggers"][handler_name] = {
 | 
					    LOGGING["loggers"][handler_name] = {
 | 
				
			||||||
        "handlers": ["console"],
 | 
					        "handlers": ["console"],
 | 
				
			||||||
        "level": level,
 | 
					        "level": level,
 | 
				
			||||||
        "propagate": True,
 | 
					        "propagate": False,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TEST = False
 | 
					TEST = False
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block title %}
 | 
					{% block title %}
 | 
				
			||||||
{% title 'Authorize Application' %}
 | 
					{% trans 'Authorize Application' %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block card %}
 | 
					{% block card %}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,2 +1,2 @@
 | 
				
			|||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
					<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
				
			||||||
  width="270px" height="20px" viewBox="0 0 150 10" enable-background="new 0 0 270 10" xml:space="preserve"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#fff;}</style></defs><g class="cls-1"><path class="cls-2" d="M1.65,11V2.45H2.87V3a2.81,2.81,0,0,1,.47-.45A1.13,1.13,0,0,1,4,2.38,1.11,1.11,0,0,1,5.1,3a1.55,1.55,0,0,1,.16.5,5.61,5.61,0,0,1,0,.81V6.58c0,.45,0,.77,0,1a1.17,1.17,0,0,1-.55.9,1.23,1.23,0,0,1-.7.16,1.35,1.35,0,0,1-.64-.16A1.53,1.53,0,0,1,2.89,8h0v3ZM4.08,4.43a1.21,1.21,0,0,0-.14-.6.51.51,0,0,0-.46-.22A.54.54,0,0,0,3,3.82a.8.8,0,0,0-.17.54V6.73A.68.68,0,0,0,3,7.2a.6.6,0,0,0,.44.18A.53.53,0,0,0,4,7.17a1,1,0,0,0,.12-.5Z"/><path class="cls-2" d="M8.63,8.54V7.91h0a2.24,2.24,0,0,1-.48.52,1.13,1.13,0,0,1-.69.18A1.39,1.39,0,0,1,7,8.54a1.09,1.09,0,0,1-.43-.24,1.32,1.32,0,0,1-.33-.49A2.33,2.33,0,0,1,6.11,7a4.89,4.89,0,0,1,.08-.91,1.51,1.51,0,0,1,.31-.65,1.44,1.44,0,0,1,.59-.38A3.19,3.19,0,0,1,8,4.93h.59V4.33a1,1,0,0,0-.13-.52A.52.52,0,0,0,8,3.61a.71.71,0,0,0-.44.15.78.78,0,0,0-.26.46H6.13A2,2,0,0,1,6.69,2.9a1.73,1.73,0,0,1,.57-.38A2,2,0,0,1,8,2.38a2.18,2.18,0,0,1,.72.12,1.71,1.71,0,0,1,.59.36,2,2,0,0,1,.38.6,2.18,2.18,0,0,1,.14.84V8.54Zm0-2.62-.34,0a1.2,1.2,0,0,0-.67.18.76.76,0,0,0-.29.68.89.89,0,0,0,.17.56A.55.55,0,0,0,8,7.53a.63.63,0,0,0,.49-.2.91.91,0,0,0,.17-.58Z"/><path class="cls-2" d="M13,4.16a.59.59,0,0,0-.2-.47.65.65,0,0,0-.42-.16.59.59,0,0,0-.45.19.66.66,0,0,0-.15.43.8.8,0,0,0,.08.33.85.85,0,0,0,.44.29l.71.29a1.73,1.73,0,0,1,.95.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.56,1.56,0,0,1-.58.39,1.88,1.88,0,0,1-2-.32,1.58,1.58,0,0,1-.4-.57,1.81,1.81,0,0,1-.17-.8h1.15a1.11,1.11,0,0,0,.17.47.56.56,0,0,0,.49.22.71.71,0,0,0,.47-.18A.59.59,0,0,0,13,6.8a.69.69,0,0,0-.13-.43,1.08,1.08,0,0,0-.48-.32l-.59-.21a2.08,2.08,0,0,1-.9-.64,1.66,1.66,0,0,1-.33-1,1.89,1.89,0,0,1,.14-.72,1.78,1.78,0,0,1,.4-.57,1.5,1.5,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.6,1.6,0,0,1,.54.38,1.85,1.85,0,0,1,.36.57,1.82,1.82,0,0,1,.13.7Z"/><path class="cls-2" d="M17.2,4.16a.63.63,0,0,0-.2-.47.69.69,0,0,0-.43-.16.55.55,0,0,0-.44.19.62.62,0,0,0-.16.43.68.68,0,0,0,.09.33.81.81,0,0,0,.43.29l.72.29a1.7,1.7,0,0,1,.94.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.61,1.61,0,0,1-.57.39,1.81,1.81,0,0,1-.74.15,1.76,1.76,0,0,1-1.24-.47,1.61,1.61,0,0,1-.41-.57,2,2,0,0,1-.17-.8h1.15a1.12,1.12,0,0,0,.18.47.53.53,0,0,0,.48.22.72.72,0,0,0,.48-.18.59.59,0,0,0,.21-.48.69.69,0,0,0-.14-.43,1,1,0,0,0-.48-.32l-.58-.21a2.06,2.06,0,0,1-.91-.64,1.66,1.66,0,0,1-.33-1A1.89,1.89,0,0,1,15,3.44a1.78,1.78,0,0,1,.4-.57,1.58,1.58,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.75,1.75,0,0,1,.55.38,1.85,1.85,0,0,1,.36.57,2,2,0,0,1,.13.7Z"/><path class="cls-2" d="M19.2,8.54V0h1.22V3h0a1.53,1.53,0,0,1,.48-.47,1.39,1.39,0,0,1,.65-.16,1.26,1.26,0,0,1,.69.16,1.35,1.35,0,0,1,.4.39,1.18,1.18,0,0,1,.15.51,7.72,7.72,0,0,1,0,1V6.73a5.56,5.56,0,0,1-.05.8,1.56,1.56,0,0,1-.15.5,1.12,1.12,0,0,1-1.07.58,1.15,1.15,0,0,1-.7-.18A3.79,3.79,0,0,1,20.42,8v.55Zm2.44-4.21a1,1,0,0,0-.13-.51A.5.5,0,0,0,21,3.61a.57.57,0,0,0-.44.18.66.66,0,0,0-.18.48V6.63a.83.83,0,0,0,.17.54.52.52,0,0,0,.45.21.49.49,0,0,0,.45-.22,1.11,1.11,0,0,0,.15-.6Z"/><path class="cls-2" d="M23.76,4.49a4.83,4.83,0,0,1,0-.68A1.55,1.55,0,0,1,24,3.26a1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24A1.59,1.59,0,0,1,24,7.73a1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1,0-.68ZM25,6.69a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17A.55.55,0,0,0,26,7.21a.72.72,0,0,0,.16-.52V4.3A.74.74,0,0,0,26,3.78a.55.55,0,0,0-.44-.17.53.53,0,0,0-.43.17A.74.74,0,0,0,25,4.3Z"/><path class="cls-2" d="M28.2,4.49a4.83,4.83,0,0,1,.05-.68,1.55,1.55,0,0,1,.18-.55,1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24,1.59,1.59,0,0,1-.62-.64,1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1-.05-.68Zm1.22,2.2a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17.55.55,0,0,0,.44-.17.72.72,0,0,0,.16-.52V4.3a.74.74,0,0,0-.16-.52A.55.55,0,0,0,30,3.61a.53.53,0,0,0-.43.17.74.74,0,0,0-.17.52Z"/><path class="cls-2" d="M32.75,8.54V0H34V5.11h0l1.47-2.66H36.7L35.24,4.93,37,8.54H35.66l-1.1-2.63L34,6.83V8.54Z"/></g></svg>
 | 
					  width="120px" height="20px" viewBox="15 0 10 10" enable-background="new 0 0 270 10" xml:space="preserve"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#fff;}</style></defs><g class="cls-1"><path class="cls-2" d="M1.65,11V2.45H2.87V3a2.81,2.81,0,0,1,.47-.45A1.13,1.13,0,0,1,4,2.38,1.11,1.11,0,0,1,5.1,3a1.55,1.55,0,0,1,.16.5,5.61,5.61,0,0,1,0,.81V6.58c0,.45,0,.77,0,1a1.17,1.17,0,0,1-.55.9,1.23,1.23,0,0,1-.7.16,1.35,1.35,0,0,1-.64-.16A1.53,1.53,0,0,1,2.89,8h0v3ZM4.08,4.43a1.21,1.21,0,0,0-.14-.6.51.51,0,0,0-.46-.22A.54.54,0,0,0,3,3.82a.8.8,0,0,0-.17.54V6.73A.68.68,0,0,0,3,7.2a.6.6,0,0,0,.44.18A.53.53,0,0,0,4,7.17a1,1,0,0,0,.12-.5Z"/><path class="cls-2" d="M8.63,8.54V7.91h0a2.24,2.24,0,0,1-.48.52,1.13,1.13,0,0,1-.69.18A1.39,1.39,0,0,1,7,8.54a1.09,1.09,0,0,1-.43-.24,1.32,1.32,0,0,1-.33-.49A2.33,2.33,0,0,1,6.11,7a4.89,4.89,0,0,1,.08-.91,1.51,1.51,0,0,1,.31-.65,1.44,1.44,0,0,1,.59-.38A3.19,3.19,0,0,1,8,4.93h.59V4.33a1,1,0,0,0-.13-.52A.52.52,0,0,0,8,3.61a.71.71,0,0,0-.44.15.78.78,0,0,0-.26.46H6.13A2,2,0,0,1,6.69,2.9a1.73,1.73,0,0,1,.57-.38A2,2,0,0,1,8,2.38a2.18,2.18,0,0,1,.72.12,1.71,1.71,0,0,1,.59.36,2,2,0,0,1,.38.6,2.18,2.18,0,0,1,.14.84V8.54Zm0-2.62-.34,0a1.2,1.2,0,0,0-.67.18.76.76,0,0,0-.29.68.89.89,0,0,0,.17.56A.55.55,0,0,0,8,7.53a.63.63,0,0,0,.49-.2.91.91,0,0,0,.17-.58Z"/><path class="cls-2" d="M13,4.16a.59.59,0,0,0-.2-.47.65.65,0,0,0-.42-.16.59.59,0,0,0-.45.19.66.66,0,0,0-.15.43.8.8,0,0,0,.08.33.85.85,0,0,0,.44.29l.71.29a1.73,1.73,0,0,1,.95.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.56,1.56,0,0,1-.58.39,1.88,1.88,0,0,1-2-.32,1.58,1.58,0,0,1-.4-.57,1.81,1.81,0,0,1-.17-.8h1.15a1.11,1.11,0,0,0,.17.47.56.56,0,0,0,.49.22.71.71,0,0,0,.47-.18A.59.59,0,0,0,13,6.8a.69.69,0,0,0-.13-.43,1.08,1.08,0,0,0-.48-.32l-.59-.21a2.08,2.08,0,0,1-.9-.64,1.66,1.66,0,0,1-.33-1,1.89,1.89,0,0,1,.14-.72,1.78,1.78,0,0,1,.4-.57,1.5,1.5,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.6,1.6,0,0,1,.54.38,1.85,1.85,0,0,1,.36.57,1.82,1.82,0,0,1,.13.7Z"/><path class="cls-2" d="M17.2,4.16a.63.63,0,0,0-.2-.47.69.69,0,0,0-.43-.16.55.55,0,0,0-.44.19.62.62,0,0,0-.16.43.68.68,0,0,0,.09.33.81.81,0,0,0,.43.29l.72.29a1.7,1.7,0,0,1,.94.72,2,2,0,0,1,.26,1,1.85,1.85,0,0,1-.52,1.3,1.61,1.61,0,0,1-.57.39,1.81,1.81,0,0,1-.74.15,1.76,1.76,0,0,1-1.24-.47,1.61,1.61,0,0,1-.41-.57,2,2,0,0,1-.17-.8h1.15a1.12,1.12,0,0,0,.18.47.53.53,0,0,0,.48.22.72.72,0,0,0,.48-.18.59.59,0,0,0,.21-.48.69.69,0,0,0-.14-.43,1,1,0,0,0-.48-.32l-.58-.21a2.06,2.06,0,0,1-.91-.64,1.66,1.66,0,0,1-.33-1A1.89,1.89,0,0,1,15,3.44a1.78,1.78,0,0,1,.4-.57,1.58,1.58,0,0,1,.56-.36,1.82,1.82,0,0,1,.7-.13,1.93,1.93,0,0,1,.69.13,1.75,1.75,0,0,1,.55.38,1.85,1.85,0,0,1,.36.57,2,2,0,0,1,.13.7Z"/><path class="cls-2" d="M19.2,8.54V0h1.22V3h0a1.53,1.53,0,0,1,.48-.47,1.39,1.39,0,0,1,.65-.16,1.26,1.26,0,0,1,.69.16,1.35,1.35,0,0,1,.4.39,1.18,1.18,0,0,1,.15.51,7.72,7.72,0,0,1,0,1V6.73a5.56,5.56,0,0,1-.05.8,1.56,1.56,0,0,1-.15.5,1.12,1.12,0,0,1-1.07.58,1.15,1.15,0,0,1-.7-.18A3.79,3.79,0,0,1,20.42,8v.55Zm2.44-4.21a1,1,0,0,0-.13-.51A.5.5,0,0,0,21,3.61a.57.57,0,0,0-.44.18.66.66,0,0,0-.18.48V6.63a.83.83,0,0,0,.17.54.52.52,0,0,0,.45.21.49.49,0,0,0,.45-.22,1.11,1.11,0,0,0,.15-.6Z"/><path class="cls-2" d="M23.76,4.49a4.83,4.83,0,0,1,0-.68A1.55,1.55,0,0,1,24,3.26a1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24A1.59,1.59,0,0,1,24,7.73a1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1,0-.68ZM25,6.69a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17A.55.55,0,0,0,26,7.21a.72.72,0,0,0,.16-.52V4.3A.74.74,0,0,0,26,3.78a.55.55,0,0,0-.44-.17.53.53,0,0,0-.43.17A.74.74,0,0,0,25,4.3Z"/><path class="cls-2" d="M28.2,4.49a4.83,4.83,0,0,1,.05-.68,1.55,1.55,0,0,1,.18-.55,1.59,1.59,0,0,1,.62-.64,1.84,1.84,0,0,1,1-.24,1.87,1.87,0,0,1,1,.24,1.59,1.59,0,0,1,.62.64,1.55,1.55,0,0,1,.18.55,4.83,4.83,0,0,1,.05.68v2a4.72,4.72,0,0,1-.05.68,1.55,1.55,0,0,1-.18.55,1.59,1.59,0,0,1-.62.64,1.87,1.87,0,0,1-1,.24,1.84,1.84,0,0,1-1-.24,1.59,1.59,0,0,1-.62-.64,1.55,1.55,0,0,1-.18-.55,4.72,4.72,0,0,1-.05-.68Zm1.22,2.2a.72.72,0,0,0,.17.52.53.53,0,0,0,.43.17.55.55,0,0,0,.44-.17.72.72,0,0,0,.16-.52V4.3a.74.74,0,0,0-.16-.52A.55.55,0,0,0,30,3.61a.53.53,0,0,0-.43.17.74.74,0,0,0-.17.52Z"/><path class="cls-2" d="M32.75,8.54V0H34V5.11h0l1.47-2.66H36.7L35.24,4.93,37,8.54H35.66l-1.1-2.63L34,6.83V8.54Z"/></g></svg>
 | 
				
			||||||
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB  | 
@ -197,3 +197,117 @@ form .form-row p.datetime {
 | 
				
			|||||||
input[data-is-monospace] {
 | 
					input[data-is-monospace] {
 | 
				
			||||||
    font-family: monospace;
 | 
					    font-family: monospace;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header {
 | 
				
			||||||
 | 
					    background-color: #151515;
 | 
				
			||||||
 | 
					    min-height: auto
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (min-width: 992px) {
 | 
				
			||||||
 | 
					    .ws-page-header .pf-c-page__header-nav {
 | 
				
			||||||
 | 
					        margin-left:12px
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header .pf-c-nav__scroll-button {
 | 
				
			||||||
 | 
					    outline-offset: -4px;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    top: 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__item {
 | 
				
			||||||
 | 
					    margin-right: 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link {
 | 
				
			||||||
 | 
					    padding-top: 22px;
 | 
				
			||||||
 | 
					    padding-right: var(--pf-global--spacer--md);
 | 
				
			||||||
 | 
					    padding-left: var(--pf-global--spacer--md);
 | 
				
			||||||
 | 
					    color: var(--pf-global--Color--light-100)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (max-width: 991px) {
 | 
				
			||||||
 | 
					    .ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link {
 | 
				
			||||||
 | 
					        padding-top:10px
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:after {
 | 
				
			||||||
 | 
					    top: 0!important;
 | 
				
			||||||
 | 
					    height: 4px
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:active,.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:hover {
 | 
				
			||||||
 | 
					    -webkit-transition: .5s;
 | 
				
			||||||
 | 
					    transition: .5s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link.pf-m-current,.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:active,.ws-page-header .pf-c-nav__horizontal-list .pf-c-nav__link:hover {
 | 
				
			||||||
 | 
					    background-color: var(--pf-global--BackgroundColor--light-100);
 | 
				
			||||||
 | 
					    color: #151515!important;
 | 
				
			||||||
 | 
					    font-weight: var(--pf-global--FontWeight--normal)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header li a:after {
 | 
				
			||||||
 | 
					    content: "";
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    left: 50%!important;
 | 
				
			||||||
 | 
					    bottom: 0;
 | 
				
			||||||
 | 
					    -webkit-transform: translateX(-50%) scaleX(0);
 | 
				
			||||||
 | 
					    transform: translateX(-50%) scaleX(0);
 | 
				
			||||||
 | 
					    -webkit-transform-origin: 50% 50%;
 | 
				
			||||||
 | 
					    transform-origin: 50% 50%;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    height: 1px;
 | 
				
			||||||
 | 
					    background-color: var(--pf-global--BackgroundColor--light-100);
 | 
				
			||||||
 | 
					    color: #151515!important;
 | 
				
			||||||
 | 
					    -webkit-transition: -webkit-transform .25s;
 | 
				
			||||||
 | 
					    transition: -webkit-transform .25s;
 | 
				
			||||||
 | 
					    transition: transform .25s;
 | 
				
			||||||
 | 
					    transition: transform .25s,-webkit-transform .25s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header li a:hover:after {
 | 
				
			||||||
 | 
					    -webkit-transform: translateX(-50%) scaleX(1);
 | 
				
			||||||
 | 
					    transform: translateX(-50%) scaleX(1)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header li a.pf-m-current:after {
 | 
				
			||||||
 | 
					    left: 0!important;
 | 
				
			||||||
 | 
					    -webkit-transform: none;
 | 
				
			||||||
 | 
					    transform: none
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-sidebar#page-sidebar {
 | 
				
			||||||
 | 
					    color: #fff;
 | 
				
			||||||
 | 
					    box-shadow: none
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-sidebar .pf-c-nav {
 | 
				
			||||||
 | 
					    margin-top: 16px
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pf-site-search {
 | 
				
			||||||
 | 
					    padding: 0 0 2px;
 | 
				
			||||||
 | 
					    width: 150px;
 | 
				
			||||||
 | 
					    background: transparent;
 | 
				
			||||||
 | 
					    -webkit-transition: .25s;
 | 
				
			||||||
 | 
					    transition: .25s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ws-page-header .pf-c-page__header-brand-toggle {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					    visibility: hidden
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media (max-width: 768px) {
 | 
				
			||||||
 | 
					    .pf-site-search {
 | 
				
			||||||
 | 
					        width:100px
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .ws-page-header .pf-c-page__header-brand-toggle {
 | 
				
			||||||
 | 
					        display: block;
 | 
				
			||||||
 | 
					        visibility: visible
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user