Compare commits
23 Commits
version/0.
...
version/0.
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e46c8bfec | |||
| 1eaa9b9733 | |||
| ee05834b69 | |||
| fccc8f4959 | |||
| c721620f96 | |||
| c9f73d718e | |||
| bfa58be721 | |||
| 4bb602149e | |||
| 81ab9092fc | |||
| 29d5962c4c | |||
| 5c75339946 | |||
| 4774d9a46c | |||
| dbe16ba4fd | |||
| 6972cf00a0 | |||
| 0445be9712 | |||
| 89dbdd9585 | |||
| da88ce7150 | |||
| 5f50fcfcf5 | |||
| 96be087221 | |||
| a53a269a8c | |||
| 59565a5286 | |||
| ae3c092238 | |||
| e98e5e4e3e |
@ -1,5 +1,5 @@
|
|||||||
[bumpversion]
|
[bumpversion]
|
||||||
current_version = 0.1.19-beta
|
current_version = 0.1.23-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>.*)
|
||||||
|
|||||||
@ -54,7 +54,7 @@ package-docker:
|
|||||||
before_script:
|
before_script:
|
||||||
- echo "{\"auths\":{\"docker.$NEXUS_URL\":{\"auth\":\"$NEXUS_AUTH\"}}}" > /kaniko/.docker/config.json
|
- echo "{\"auths\":{\"docker.$NEXUS_URL\":{\"auth\":\"$NEXUS_AUTH\"}}}" > /kaniko/.docker/config.json
|
||||||
script:
|
script:
|
||||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.pkg.beryju.org/passbook:latest --destination docker.pkg.beryju.org/passbook:0.1.19-beta
|
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination docker.pkg.beryju.org/passbook:latest --destination docker.pkg.beryju.org/passbook:0.1.23-beta
|
||||||
stage: build
|
stage: build
|
||||||
only:
|
only:
|
||||||
- tags
|
- tags
|
||||||
|
|||||||
@ -3,7 +3,7 @@ from setuptools import setup
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='django-allauth-passbook',
|
name='django-allauth-passbook',
|
||||||
version='0.1.19-beta',
|
version='0.1.23-beta',
|
||||||
description='passbook support for django-allauth',
|
description='passbook support for django-allauth',
|
||||||
# long_description='\n'.join(read_simple('docs/index.md')[2:]),
|
# long_description='\n'.join(read_simple('docs/index.md')[2:]),
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
|
|||||||
@ -18,7 +18,7 @@ tests_require = [
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='sentry-auth-passbook',
|
name='sentry-auth-passbook',
|
||||||
version='0.1.19-beta',
|
version='0.1.23-beta',
|
||||||
author='BeryJu.org',
|
author='BeryJu.org',
|
||||||
author_email='support@beryju.org',
|
author_email='support@beryju.org',
|
||||||
url='https://passbook.beryju.org',
|
url='https://passbook.beryju.org',
|
||||||
|
|||||||
35
debian/changelog
vendored
@ -1,3 +1,38 @@
|
|||||||
|
passbook (0.1.23) stable; urgency=medium
|
||||||
|
|
||||||
|
* add support for OpenID-Connect Discovery
|
||||||
|
|
||||||
|
-- Jens Langhammer <jens.langhammer@beryju.org> Thu, 18 Mar 2019 20:19:27 +0000
|
||||||
|
|
||||||
|
passbook (0.1.22) stable; urgency=medium
|
||||||
|
|
||||||
|
* bump version: 0.1.20-beta -> 0.1.21-beta
|
||||||
|
* fix missing debug template
|
||||||
|
* move icons to single folder, cleanup
|
||||||
|
* fix layout when on mobile viewport and scrolling
|
||||||
|
* fix delete form not working
|
||||||
|
* point to correct icons
|
||||||
|
* add Azure AD Source
|
||||||
|
* Fix OAuth Client's disconnect view having invalid URL names
|
||||||
|
|
||||||
|
-- Jens Langhammer <jens.langhammer@beryju.org> Thu, 14 Mar 2019 20:19:27 +0000
|
||||||
|
|
||||||
|
passbook (0.1.21) stable; urgency=medium
|
||||||
|
|
||||||
|
* bump version: 0.1.19-beta -> 0.1.20-beta
|
||||||
|
* add request debug view
|
||||||
|
* detect HTTPS from reverse proxy
|
||||||
|
|
||||||
|
-- Jens Langhammer <jens.langhammer@beryju.org> Thu, 14 Mar 2019 17:01:49 +0000
|
||||||
|
|
||||||
|
passbook (0.1.20) stable; urgency=medium
|
||||||
|
|
||||||
|
* bump version: 0.1.18-beta -> 0.1.19-beta
|
||||||
|
* fix GitHub Pretend again
|
||||||
|
* add user settings for Sources
|
||||||
|
|
||||||
|
-- Jens Langhammer <jens.langhammer@beryju.org> Wed, 13 Mar 2019 15:49:44 +0000
|
||||||
|
|
||||||
passbook (0.1.18) stable; urgency=medium
|
passbook (0.1.18) stable; urgency=medium
|
||||||
|
|
||||||
* bump version: 0.1.16-beta -> 0.1.17-beta
|
* bump version: 0.1.16-beta -> 0.1.17-beta
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
appVersion: "0.1.19-beta"
|
appVersion: "0.1.23-beta"
|
||||||
description: A Helm chart for passbook.
|
description: A Helm chart for passbook.
|
||||||
name: passbook
|
name: passbook
|
||||||
version: "0.1.19-beta"
|
version: "0.1.23-beta"
|
||||||
icon: https://passbook.beryju.org/images/logo.png
|
icon: https://passbook.beryju.org/images/logo.png
|
||||||
|
|||||||
@ -123,6 +123,7 @@ data:
|
|||||||
- passbook.oauth_client.source_types.reddit
|
- passbook.oauth_client.source_types.reddit
|
||||||
- passbook.oauth_client.source_types.supervisr
|
- passbook.oauth_client.source_types.supervisr
|
||||||
- passbook.oauth_client.source_types.twitter
|
- passbook.oauth_client.source_types.twitter
|
||||||
|
- passbook.oauth_client.source_types.azure_ad
|
||||||
saml_idp:
|
saml_idp:
|
||||||
signing: true
|
signing: true
|
||||||
autosubmit: false
|
autosubmit: false
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
replicaCount: 1
|
replicaCount: 1
|
||||||
|
|
||||||
image:
|
image:
|
||||||
tag: 0.1.19-beta
|
tag: 0.1.23-beta
|
||||||
|
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook"""
|
"""passbook"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook admin"""
|
"""passbook admin"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
31
passbook/admin/templates/administration/debug/request.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% extends "administration/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load utils %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% title %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<h1><span class="pficon-applications"></span> {% trans "Request" %}</h1>
|
||||||
|
<hr>
|
||||||
|
<table class="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans 'Key' %}</th>
|
||||||
|
<th>{% trans 'Value' %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for key, value in request_dict.items %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ key }}</td>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
"""passbook URL Configuration"""
|
"""passbook URL Configuration"""
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
from passbook.admin.views import (applications, audit, factors, groups,
|
from passbook.admin.views import (applications, audit, debug, factors, groups,
|
||||||
invitations, overview, policy,
|
invitations, overview, policy,
|
||||||
property_mapping, providers, sources, users)
|
property_mapping, providers, sources, users)
|
||||||
|
|
||||||
@ -77,5 +77,7 @@ urlpatterns = [
|
|||||||
# Groups
|
# Groups
|
||||||
path('groups/', groups.GroupListView.as_view(), name='groups'),
|
path('groups/', groups.GroupListView.as_view(), name='groups'),
|
||||||
# API
|
# API
|
||||||
path('api/', include('passbook.admin.api.urls'))
|
path('api/', include('passbook.admin.api.urls')),
|
||||||
|
# Debug
|
||||||
|
path('debug/request/', debug.DebugRequestView.as_view(), name='debug-request'),
|
||||||
]
|
]
|
||||||
|
|||||||
17
passbook/admin/views/debug.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
"""passbook administration debug views"""
|
||||||
|
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
from passbook.admin.mixins import AdminRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
|
class DebugRequestView(AdminRequiredMixin, TemplateView):
|
||||||
|
"""Show debug info about request"""
|
||||||
|
|
||||||
|
template_name = 'administration/debug/request.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
kwargs['request_dict'] = {}
|
||||||
|
for key in dir(self.request):
|
||||||
|
kwargs['request_dict'][key] = getattr(self.request, key)
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook api"""
|
"""passbook api"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook audit Header"""
|
"""passbook audit Header"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook captcha_factor Header"""
|
"""passbook captcha_factor Header"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook core"""
|
"""passbook core"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -186,6 +186,12 @@ class Source(PolicyModel):
|
|||||||
"""Return additional Info, such as a callback URL. Show in the administration interface."""
|
"""Return additional Info, such as a callback URL. Show in the administration interface."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def has_user_settings(self):
|
||||||
|
"""Entrypoint to integrate with User settings. Can either return False if no
|
||||||
|
user settings are available, or a tuple or string, string, string where the first string
|
||||||
|
is the name the item has, the second string is the icon and the third is the view-name."""
|
||||||
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ SECRET_KEY = CONFIG.get('secret_key')
|
|||||||
DEBUG = CONFIG.get('debug')
|
DEBUG = CONFIG.get('debug')
|
||||||
INTERNAL_IPS = ['127.0.0.1']
|
INTERNAL_IPS = ['127.0.0.1']
|
||||||
ALLOWED_HOSTS = CONFIG.get('domains', [])
|
ALLOWED_HOSTS = CONFIG.get('domains', [])
|
||||||
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
|
|
||||||
LOGIN_URL = 'passbook_core:auth-login'
|
LOGIN_URL = 'passbook_core:auth-login'
|
||||||
# CSRF_FAILURE_VIEW = 'passbook.core.views.errors.CSRFErrorView.as_view'
|
# CSRF_FAILURE_VIEW = 'passbook.core.views.errors.CSRFErrorView.as_view'
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
|
||||||
<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="20px" height="20px" viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
|
|
||||||
<style type="text/css">
|
|
||||||
.st0{fill:#FBBB00;}
|
|
||||||
.st1{fill:#518EF8;}
|
|
||||||
.st2{fill:#28B446;}
|
|
||||||
.st3{fill:#F14336;}
|
|
||||||
</style>
|
|
||||||
<path class="st0" d="M4.4,12.1l-0.7,2.6l-2.5,0.1C0.4,13.3,0,11.7,0,10c0-1.7,0.4-3.2,1.1-4.6h0l2.3,0.4l1,2.3
|
|
||||||
C4.2,8.7,4.1,9.3,4.1,10C4.1,10.7,4.2,11.4,4.4,12.1z"/>
|
|
||||||
<path class="st1" d="M19.8,8.1C19.9,8.7,20,9.4,20,10c0,0.7-0.1,1.4-0.2,2.1c-0.5,2.3-1.8,4.3-3.5,5.7l0,0l-2.9-0.1L13,15.1
|
|
||||||
c1.2-0.7,2.1-1.8,2.6-3h-5.3v-4h5.4H19.8L19.8,8.1z"/>
|
|
||||||
<path class="st2" d="M16.3,17.8L16.3,17.8C14.5,19.2,12.4,20,10,20c-3.8,0-7.1-2.1-8.8-5.3l3.2-2.7c0.8,2.3,3,3.9,5.6,3.9
|
|
||||||
c1.1,0,2.1-0.3,3-0.8L16.3,17.8z"/>
|
|
||||||
<path class="st3" d="M16.4,2.3L13.1,5c-0.9-0.6-2-0.9-3.1-0.9c-2.6,0-4.8,1.7-5.6,4L1.1,5.4h0C2.8,2.2,6.1,0,10,0
|
|
||||||
C12.4,0,14.7,0.9,16.4,2.3z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
1
passbook/core/static/img/logos/azure ad.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21"><title>MS-SymbolLockup</title><rect x="1" y="1" width="9" height="9" fill="#f25022"/><rect x="1" y="11" width="9" height="9" fill="#00a4ef"/><rect x="11" y="1" width="9" height="9" fill="#7fba00"/><rect x="11" y="11" width="9" height="9" fill="#ffb900"/></svg>
|
||||||
|
After Width: | Height: | Size: 343 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 750 B After Width: | Height: | Size: 750 B |
|
Before Width: | Height: | Size: 814 B After Width: | Height: | Size: 814 B |
|
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 788 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 783 B |
|
Before Width: | Height: | Size: 688 B After Width: | Height: | Size: 688 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 889 B |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
@ -3,7 +3,7 @@
|
|||||||
{% load utils %}
|
{% load utils %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" class="layout-pf layout-pf-fixed transitions">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
Are you sure you want to delete {{ object_type }} "{{ object }}"?
|
Are you sure you want to delete {{ object_type }} "{{ object }}"?
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
|
<input type="hidden" name="confirmdelete" value="yes">
|
||||||
<a href="{% back %}" class="btn btn-default">{% trans 'Back' %}</a>
|
<a href="{% back %}" class="btn btn-default">{% trans 'Back' %}</a>
|
||||||
<input type="submit" class="btn btn-danger" value="{% trans 'Delete' %}" />
|
<input type="submit" class="btn btn-danger" value="{% trans 'Delete' %}" />
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@ -51,7 +51,7 @@
|
|||||||
{% for url, icon, name in sources %}
|
{% for url, icon, name in sources %}
|
||||||
<li class="login-pf-social-link">
|
<li class="login-pf-social-link">
|
||||||
<a href="{{ url }}">
|
<a href="{{ url }}">
|
||||||
<img src="{% static 'img/' %}{{ icon }}.svg" alt="{{ name }}"> {{ name }}
|
<img src="{% static 'img/logos/' %}{{ icon }}.svg" alt="{{ name }}"> {{ name }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<button class="btn btn-link dropdown-toggle nav-item-iconic" id="dropdownMenu1" data-toggle="dropdown"
|
<button class="btn btn-link dropdown-toggle nav-item-iconic" id="dropdownMenu1" data-toggle="dropdown"
|
||||||
aria-haspopup="true" aria-expanded="true">
|
aria-haspopup="true" aria-expanded="true">
|
||||||
<span title="Help" class="fa pficon-help dropdown-title"></span>
|
<span title="Help" class="fa pficon-help"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
|
||||||
{% comment %} <li><a href="#0">Help</a></li> {% endcomment %}
|
{% comment %} <li><a href="#0">Help</a></li> {% endcomment %}
|
||||||
@ -172,19 +172,27 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="list-group-item {% is_active 'passbook_admin:debug-request' %}">
|
||||||
|
<a href="{% url 'passbook_admin:debug-request' %}">
|
||||||
|
<span class="list-group-item-value">
|
||||||
|
{% trans 'Debug' %}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="container-fluid container-cards-pf">
|
<div class="container-fluid container-cards-pf container-pf-nav-pf-vertical hide-nav-pf">
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
|
{{ block.super }}
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
// initialize tooltips
|
// initialize tooltips
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load is_active %}
|
{% load is_active %}
|
||||||
|
{% load static %}
|
||||||
{% load passbook_user_settings %}
|
{% load passbook_user_settings %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@ -24,6 +25,15 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
<li class="nav-divider"></li>
|
||||||
|
{% user_sources as us %}
|
||||||
|
{% for name, icon, link in us %}
|
||||||
|
<li class="{% if link == request.get_full_path %} active {% endif %}">
|
||||||
|
<a href="{{ link }}">
|
||||||
|
<i class="{{ icon }}"></i> {{ name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
from passbook.core.models import Factor
|
from passbook.core.models import Factor, Source
|
||||||
from passbook.core.policies import PolicyEngine
|
from passbook.core.policies import PolicyEngine
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
@ -20,3 +20,17 @@ def user_factors(context):
|
|||||||
if policy_engine.passing and _link:
|
if policy_engine.passing and _link:
|
||||||
matching_factors.append(_link)
|
matching_factors.append(_link)
|
||||||
return matching_factors
|
return matching_factors
|
||||||
|
|
||||||
|
@register.simple_tag(takes_context=True)
|
||||||
|
def user_sources(context):
|
||||||
|
"""Return a list of all sources which are enabled for the user"""
|
||||||
|
user = context.get('request').user
|
||||||
|
_all_sources = Source.objects.filter(enabled=True).select_subclasses()
|
||||||
|
matching_sources = []
|
||||||
|
for factor in _all_sources:
|
||||||
|
_link = factor.has_user_settings()
|
||||||
|
policy_engine = PolicyEngine(factor.policies.all())
|
||||||
|
policy_engine.for_user(user).with_request(context.get('request')).build()
|
||||||
|
if policy_engine.passing and _link:
|
||||||
|
matching_sources.append(_link)
|
||||||
|
return matching_sources
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook hibp_policy"""
|
"""passbook hibp_policy"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""Passbook ldap app Header"""
|
"""Passbook ldap app Header"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook lib"""
|
"""passbook lib"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -85,6 +85,7 @@ oauth_client:
|
|||||||
- passbook.oauth_client.source_types.reddit
|
- passbook.oauth_client.source_types.reddit
|
||||||
- passbook.oauth_client.source_types.supervisr
|
- passbook.oauth_client.source_types.supervisr
|
||||||
- passbook.oauth_client.source_types.twitter
|
- passbook.oauth_client.source_types.twitter
|
||||||
|
- passbook.oauth_client.source_types.azure_ad
|
||||||
saml_idp:
|
saml_idp:
|
||||||
# List of python packages with provider types to load.
|
# List of python packages with provider types to load.
|
||||||
types:
|
types:
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook oauth_client Header"""
|
"""passbook oauth_client Header"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -108,3 +108,17 @@ class GoogleOAuthSourceForm(OAuthSourceForm):
|
|||||||
'access_token_url': 'https://accounts.google.com/o/oauth2/token',
|
'access_token_url': 'https://accounts.google.com/o/oauth2/token',
|
||||||
'profile_url': ' https://www.googleapis.com/oauth2/v1/userinfo',
|
'profile_url': ' https://www.googleapis.com/oauth2/v1/userinfo',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AzureADOAuthSourceForm(OAuthSourceForm):
|
||||||
|
"""OAuth Source form with pre-determined URL for AzureAD"""
|
||||||
|
|
||||||
|
class Meta(OAuthSourceForm.Meta):
|
||||||
|
|
||||||
|
overrides = {
|
||||||
|
'provider_type': 'azure_ad',
|
||||||
|
'request_token_url': '',
|
||||||
|
'authorization_url': 'https://login.microsoftonline.com/common/oauth2/authorize',
|
||||||
|
'access_token_url': 'https://login.microsoftonline.com/common/oauth2/token',
|
||||||
|
'profile_url': ' https://graph.windows.net/myorganization/me?api-version=1.6',
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
"""OAuth Client models"""
|
"""OAuth Client models"""
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse, reverse_lazy
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from passbook.core.models import Source, UserSourceConnection
|
from passbook.core.models import Source, UserSourceConnection
|
||||||
@ -29,15 +29,28 @@ class OAuthSource(Source):
|
|||||||
def get_login_button(self):
|
def get_login_button(self):
|
||||||
url = reverse_lazy('passbook_oauth_client:oauth-client-login',
|
url = reverse_lazy('passbook_oauth_client:oauth-client-login',
|
||||||
kwargs={'source_slug': self.slug})
|
kwargs={'source_slug': self.slug})
|
||||||
if self.provider_type == 'github':
|
# if self.provider_type == 'github':
|
||||||
return url, 'github-logo', _('GitHub')
|
# return url, 'github-logo', _('GitHub')
|
||||||
return url, 'generic', _('Generic')
|
return url, self.provider_type, self.name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def additional_info(self):
|
def additional_info(self):
|
||||||
return "Callback URL: '%s'" % reverse_lazy('passbook_oauth_client:oauth-client-callback',
|
return "Callback URL: '%s'" % reverse_lazy('passbook_oauth_client:oauth-client-callback',
|
||||||
kwargs={'source_slug': self.slug})
|
kwargs={'source_slug': self.slug})
|
||||||
|
|
||||||
|
def has_user_settings(self):
|
||||||
|
"""Entrypoint to integrate with User settings. Can either return False if no
|
||||||
|
user settings are available, or a tuple or string, string, string where the first string
|
||||||
|
is the name the item has, the second string is the icon and the third is the view-name."""
|
||||||
|
icon_type = self.provider_type
|
||||||
|
if icon_type == 'azure ad':
|
||||||
|
icon_type = 'windows'
|
||||||
|
icon_class = 'fa fa-%s' % icon_type
|
||||||
|
view_name = 'passbook_oauth_client:oauth-client-user'
|
||||||
|
return self.name, icon_class, reverse((view_name), kwargs={
|
||||||
|
'source_slug': self.slug
|
||||||
|
})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
verbose_name = _('Generic OAuth Source')
|
verbose_name = _('Generic OAuth Source')
|
||||||
@ -103,6 +116,19 @@ class GoogleOAuthSource(OAuthSource):
|
|||||||
verbose_name = _('Google OAuth Source')
|
verbose_name = _('Google OAuth Source')
|
||||||
verbose_name_plural = _('Google OAuth Sources')
|
verbose_name_plural = _('Google OAuth Sources')
|
||||||
|
|
||||||
|
|
||||||
|
class AzureADOAuthSource(OAuthSource):
|
||||||
|
"""Abstract subclass of OAuthSource to specify AzureAD Form"""
|
||||||
|
|
||||||
|
form = 'passbook.oauth_client.forms.AzureADOAuthSourceForm'
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
abstract = True
|
||||||
|
verbose_name = _('Azure AD OAuth Source')
|
||||||
|
verbose_name_plural = _('Azure AD OAuth Sources')
|
||||||
|
|
||||||
|
|
||||||
class UserOAuthSourceConnection(UserSourceConnection):
|
class UserOAuthSourceConnection(UserSourceConnection):
|
||||||
"""Authorized remote OAuth provider."""
|
"""Authorized remote OAuth provider."""
|
||||||
|
|
||||||
|
|||||||
52
passbook/oauth_client/source_types/azure_ad.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
"""AzureAD OAuth2 Views"""
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
from logging import getLogger
|
||||||
|
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
|
||||||
|
from passbook.oauth_client.clients import OAuth2Client
|
||||||
|
from passbook.oauth_client.source_types.manager import MANAGER, RequestKind
|
||||||
|
from passbook.oauth_client.utils import user_get_or_create
|
||||||
|
from passbook.oauth_client.views.core import OAuthCallback
|
||||||
|
|
||||||
|
LOGGER = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class AzureADOAuth2Client(OAuth2Client):
|
||||||
|
"""AzureAD OAuth2 Client"""
|
||||||
|
|
||||||
|
def get_profile_info(self, raw_token):
|
||||||
|
"Fetch user profile information."
|
||||||
|
try:
|
||||||
|
token = json.loads(raw_token)['access_token']
|
||||||
|
headers = {
|
||||||
|
'Authorization': 'Bearer %s' % token
|
||||||
|
}
|
||||||
|
response = self.request('get', self.source.profile_url,
|
||||||
|
headers=headers)
|
||||||
|
response.raise_for_status()
|
||||||
|
except RequestException as exc:
|
||||||
|
LOGGER.warning('Unable to fetch user profile: %s', exc)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return response.json() or response.text
|
||||||
|
|
||||||
|
|
||||||
|
@MANAGER.source(kind=RequestKind.callback, name='Azure AD')
|
||||||
|
class AzureADOAuthCallback(OAuthCallback):
|
||||||
|
"""AzureAD OAuth2 Callback"""
|
||||||
|
|
||||||
|
client_class = AzureADOAuth2Client
|
||||||
|
|
||||||
|
def get_user_id(self, source, info):
|
||||||
|
return uuid.UUID(info.get('objectId')).int
|
||||||
|
|
||||||
|
def get_or_create_user(self, source, access, info):
|
||||||
|
user_data = {
|
||||||
|
'username': info.get('displayName'),
|
||||||
|
'email': info.get('mail', None) or info.get('otherMails')[0],
|
||||||
|
'name': info.get('displayName'),
|
||||||
|
'password': None,
|
||||||
|
}
|
||||||
|
return user_get_or_create(**user_data)
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% any_provider as enabled %}
|
|
||||||
{% if enabled %}
|
|
||||||
<div class="btn-group btn-primary btn-block">
|
|
||||||
{% endif %}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% provider_exists 'facebook' as facebook_enabled %}
|
|
||||||
{% if facebook_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='facebook' %}" class="btn" style="background-color:#4267b2;color:white;margin-top:10px;width:100%;"><i class="fa fa-facebook-official" aria-hidden="true"></i></a>
|
|
||||||
{% endif %}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% provider_exists 'twitter' as twitter_enabled %}
|
|
||||||
{% if twitter_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='twitter' %}" class="btn" style="background-color:#55ACEE;color:white;margin-top:10px;width:100%;"><i class="fa fa-twitter" aria-hidden="true"></i></a>
|
|
||||||
{% endif %}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% provider_exists 'google' as google_enabled %}
|
|
||||||
{% if google_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='google' %}" class="btn" style="background-color:white;color:black;margin-top:10px;width:100%;"><img src="{% static 'img/google.svg' %}" style="height:12px"></a>
|
|
||||||
{% endif %}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% provider_exists 'github' as github_enabled %}
|
|
||||||
{% if github_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='github' %}" class="btn" style="background-color:#444444;color:white;margin-top:10px;width:100%;"><i class="fa fa-github" aria-hidden="true"></i></a>
|
|
||||||
{% endif %}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% provider_exists 'discord' as discord_enabled %}
|
|
||||||
{% if discord_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='discord' %}" class="btn" style="background-color:#2C2F33;color:white;margin-top:10px;width:100%;"><img src="{% static 'img/discord.svg' %}" style="height:12px"></a>
|
|
||||||
{% endif %}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% provider_exists 'reddit' as reddit_enabled %}
|
|
||||||
{% if reddit_enabled %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider='reddit' %}" class="btn" style="background-color:#ff4500;color:white;margin-top:10px;width:100%;"><img src="{% static 'img/reddit.svg' %}" style="height:20px;margin-top:-5px;"></a>
|
|
||||||
{% endif %}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{% load passbook_oauth_client %}
|
|
||||||
|
|
||||||
{% any_provider as enabled %}
|
|
||||||
{% if enabled %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
{% extends "user/base.html" %}
|
|
||||||
|
|
||||||
{% load utils %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block title %}
|
|
||||||
{% title "Overview" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<h1><clr-icon shape="connect" size="48"></clr-icon>{% trans "OAuth2" %}</h1>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-header">
|
|
||||||
{% trans "Connected Accounts" %}
|
|
||||||
</div>
|
|
||||||
<div class="card-footer">
|
|
||||||
{% if provider_state %}
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<th>
|
|
||||||
<th>{% trans 'Provider' %}</th>
|
|
||||||
<th>{% trans 'Status' %}</th>
|
|
||||||
<th>{% trans 'Action' %}</th>
|
|
||||||
<th>{% trans 'ID' %}</th>
|
|
||||||
</th>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for data in provider_state %}
|
|
||||||
<tr>
|
|
||||||
<td></td>
|
|
||||||
<td>{% trans data.provider.ui_name %}</td>
|
|
||||||
<td>{{ data.state|yesno:"Connected,Not Connected" }}</td>
|
|
||||||
<td>
|
|
||||||
{% if data.state == False %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-login' provider=data.provider.name %}">Connect</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{% url 'passbook_oauth_client:oauth-client-disconnect' provider=data.provider.name %}">Disconnect</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>{{ data.aas.first.identifier }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<p>{% trans "No Providers configured!" %}</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
18
passbook/oauth_client/templates/oauth_client/user.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% extends "user/base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block page %}
|
||||||
|
<h1>{{ source.name }}</h1>
|
||||||
|
{% if connections.exists %}
|
||||||
|
<p>{% trans 'Connected.' %}</p>
|
||||||
|
<a class="btn btn-danger" href="{% url 'passbook_oauth_client:oauth-client-disconnect' source_slug=source.slug %}">
|
||||||
|
{% trans 'Disconnect' %}
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<p>Not connected.</p>
|
||||||
|
<a class="btn btn-primary" href="{% url 'passbook_oauth_client:oauth-client-login' source_slug=source.slug %}">
|
||||||
|
{% trans 'Connect' %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from passbook.oauth_client.source_types.manager import RequestKind
|
from passbook.oauth_client.source_types.manager import RequestKind
|
||||||
from passbook.oauth_client.views import core, dispatcher
|
from passbook.oauth_client.views import core, dispatcher, user
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('login/<slug:source_slug>/', dispatcher.DispatcherView.as_view(
|
path('login/<slug:source_slug>/', dispatcher.DispatcherView.as_view(
|
||||||
@ -12,4 +12,6 @@ urlpatterns = [
|
|||||||
kind=RequestKind.callback), name='oauth-client-callback'),
|
kind=RequestKind.callback), name='oauth-client-callback'),
|
||||||
path('disconnect/<slug:source_slug>/', core.DisconnectView.as_view(),
|
path('disconnect/<slug:source_slug>/', core.DisconnectView.as_view(),
|
||||||
name='oauth-client-disconnect'),
|
name='oauth-client-disconnect'),
|
||||||
|
path('user/<slug:source_slug>/', user.UserSettingsView.as_view(),
|
||||||
|
name='oauth-client-user'),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -194,7 +194,9 @@ class OAuthCallback(OAuthClientMixin, View):
|
|||||||
messages.success(self.request, _("Successfully linked %(source)s!" % {
|
messages.success(self.request, _("Successfully linked %(source)s!" % {
|
||||||
'source': self.source.name
|
'source': self.source.name
|
||||||
}))
|
}))
|
||||||
return redirect(reverse('user_settings'))
|
return redirect(reverse('passbook_oauth_client:oauth-client-user', kwargs={
|
||||||
|
'source_slug': self.source.slug
|
||||||
|
}))
|
||||||
messages.success(self.request, _("Successfully authenticated with %(source)s!" % {
|
messages.success(self.request, _("Successfully authenticated with %(source)s!" % {
|
||||||
'source': self.source.name
|
'source': self.source.name
|
||||||
}))
|
}))
|
||||||
@ -207,26 +209,28 @@ class DisconnectView(LoginRequiredMixin, View):
|
|||||||
source = None
|
source = None
|
||||||
aas = None
|
aas = None
|
||||||
|
|
||||||
def dispatch(self, request, source):
|
def dispatch(self, request, source_slug):
|
||||||
self.source = get_object_or_404(OAuthSource, name=source)
|
self.source = get_object_or_404(OAuthSource, slug=source_slug)
|
||||||
self.aas = get_object_or_404(UserOAuthSourceConnection,
|
self.aas = get_object_or_404(UserOAuthSourceConnection,
|
||||||
source=self.source, user=request.user)
|
source=self.source, user=request.user)
|
||||||
return super().dispatch(request, source)
|
return super().dispatch(request, source_slug)
|
||||||
|
|
||||||
def post(self, request, source):
|
def post(self, request, source_slug):
|
||||||
"""Delete connection object"""
|
"""Delete connection object"""
|
||||||
if 'confirmdelete' in request.POST:
|
if 'confirmdelete' in request.POST:
|
||||||
# User confirmed deletion
|
# User confirmed deletion
|
||||||
self.aas.delete()
|
self.aas.delete()
|
||||||
messages.success(request, _('Connection successfully deleted'))
|
messages.success(request, _('Connection successfully deleted'))
|
||||||
return redirect(reverse('user_settings'))
|
return redirect(reverse('passbook_oauth_client:oauth-client-user', kwargs={
|
||||||
return self.get(request, source)
|
'source_slug': self.source.slug
|
||||||
|
}))
|
||||||
|
return self.get(request, source_slug)
|
||||||
|
|
||||||
def get(self, request, source):
|
def get(self, request, source):
|
||||||
"""Show delete form"""
|
"""Show delete form"""
|
||||||
return render(request, 'generic/delete.html', {
|
return render(request, 'generic/delete.html', {
|
||||||
'object': 'OAuth Connection with %s' % self.source.name,
|
'object': self.source,
|
||||||
'delete_url': reverse('oauth-client-disconnect', kwargs={
|
'delete_url': reverse('passbook_oauth_client:oauth-client-disconnect', kwargs={
|
||||||
'source': self.source.name,
|
'source_slug': self.source.slug,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
20
passbook/oauth_client/views/user.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"""passbook oauth_client user views"""
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
from passbook.oauth_client.models import OAuthSource, UserOAuthSourceConnection
|
||||||
|
|
||||||
|
|
||||||
|
class UserSettingsView(LoginRequiredMixin, TemplateView):
|
||||||
|
"""Show user current connection state"""
|
||||||
|
|
||||||
|
template_name = 'oauth_client/user.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
source = get_object_or_404(OAuthSource, slug=self.kwargs.get('source_slug'))
|
||||||
|
connections = UserOAuthSourceConnection.objects.filter(user=self.request.user,
|
||||||
|
source=source)
|
||||||
|
kwargs['source'] = source
|
||||||
|
kwargs['connections'] = connections
|
||||||
|
return super().get_context_data(**kwargs)
|
||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook oauth_provider Header"""
|
"""passbook oauth_provider Header"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
from oauth2_provider import views
|
from oauth2_provider import views
|
||||||
|
|
||||||
from passbook.oauth_provider.views import oauth2
|
from passbook.oauth_provider.views import oauth2, openid
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Custom OAuth 2 Authorize View
|
# Custom OAuth 2 Authorize View
|
||||||
@ -14,8 +14,12 @@ urlpatterns = [
|
|||||||
path('authorize/permission_denied/', oauth2.OAuthPermissionDenied.as_view(),
|
path('authorize/permission_denied/', oauth2.OAuthPermissionDenied.as_view(),
|
||||||
name='oauth2-permission-denied'),
|
name='oauth2-permission-denied'),
|
||||||
# OAuth API
|
# OAuth API
|
||||||
path("authorize/", views.AuthorizationView.as_view(), name="authorize"),
|
|
||||||
path("token/", views.TokenView.as_view(), name="token"),
|
path("token/", views.TokenView.as_view(), name="token"),
|
||||||
path("revoke_token/", views.RevokeTokenView.as_view(), name="revoke-token"),
|
path("revoke_token/", views.RevokeTokenView.as_view(), name="revoke-token"),
|
||||||
path("introspect/", views.IntrospectTokenView.as_view(), name="introspect"),
|
path("introspect/", views.IntrospectTokenView.as_view(), name="introspect"),
|
||||||
|
# OpenID-Connect Discovery
|
||||||
|
path('.well-known/openid-configuration', openid.OpenIDConfigurationView.as_view(),
|
||||||
|
name='openid-discovery'),
|
||||||
|
path('.well-known/jwks.json', openid.JSONWebKeyView.as_view(),
|
||||||
|
name='openid-jwks'),
|
||||||
]
|
]
|
||||||
|
|||||||
30
passbook/oauth_provider/views/openid.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
"""passbook oauth provider OpenID Views"""
|
||||||
|
|
||||||
|
from django.http import HttpRequest, JsonResponse
|
||||||
|
from django.shortcuts import reverse
|
||||||
|
from django.views.generic import View
|
||||||
|
|
||||||
|
|
||||||
|
class OpenIDConfigurationView(View):
|
||||||
|
"""Return OpenID Configuration"""
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest):
|
||||||
|
"""Get Response conform to https://openid.net/specs/openid-connect-discovery-1_0.html"""
|
||||||
|
return JsonResponse({
|
||||||
|
'issuer': request.build_absolute_uri(reverse('passbook_core:overview')),
|
||||||
|
'authorization_endpoint': request.build_absolute_uri(
|
||||||
|
reverse('passbook_oauth_provider:oauth2-authorize')),
|
||||||
|
'token_endpoint': request.build_absolute_uri(reverse('passbook_oauth_provider:token')),
|
||||||
|
"jwks_uri": request.build_absolute_uri(reverse('passbook_oauth_provider:openid-jwks')),
|
||||||
|
"scopes_supported": [
|
||||||
|
"openid:userinfo",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class JSONWebKeyView(View):
|
||||||
|
"""JSON Web Key View"""
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest):
|
||||||
|
"""JSON Webkeys are not implemented yet, hence return an empty object"""
|
||||||
|
return JsonResponse({})
|
||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook otp Header"""
|
"""passbook otp Header"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook password_expiry"""
|
"""passbook password_expiry"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class GitHubUserView(View):
|
|||||||
|
|
||||||
def verify_access_token(self):
|
def verify_access_token(self):
|
||||||
"""Verify access token manually since github uses /user?access_token=..."""
|
"""Verify access token manually since github uses /user?access_token=..."""
|
||||||
token = get_object_or_404(AccessToken, token=self.request.get('access_token', ''))
|
token = get_object_or_404(AccessToken, token=self.request.GET.get('access_token', ''))
|
||||||
return token.user
|
return token.user
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
"""passbook saml_idp Header"""
|
"""passbook saml_idp Header"""
|
||||||
__version__ = '0.1.19-beta'
|
__version__ = '0.1.23-beta'
|
||||||
|
|||||||