working oidc
This commit is contained in:
parent
01d1ac23de
commit
44b409d886
@ -194,18 +194,18 @@ class User(db.Model, ModelController, UserMixin):
|
|||||||
backref=db.backref('users', lazy='dynamic'))
|
backref=db.backref('users', lazy='dynamic'))
|
||||||
|
|
||||||
|
|
||||||
class U2FCredential(db.Model, ModelController):
|
class Credential(db.Model, ModelController):
|
||||||
name = db.Column(db.Unicode)
|
name = db.Column(db.Unicode)
|
||||||
date_added = db.Column(db.DateTime)
|
date_added = db.Column(db.DateTime)
|
||||||
device = db.Column(db.Unicode)
|
device = db.Column(db.Unicode)
|
||||||
|
|
||||||
user_sso_id = db.Column(db.Integer, db.ForeignKey('user_sso.id'))
|
user_sso_id = db.Column(db.Integer, db.ForeignKey('user_s.id'))
|
||||||
user_sso = db.relationship('UserSSO',
|
user_sso = db.relationship('UserS',
|
||||||
backref=db.backref("u2f_credentials"),
|
backref=db.backref("credentials"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserSSO(db.Model, ModelController):
|
class UserS(db.Model, ModelController):
|
||||||
username = db.Column(db.Unicode, unique=True)
|
username = db.Column(db.Unicode, unique=True)
|
||||||
email = db.Column(db.Unicode, unique=True)
|
email = db.Column(db.Unicode, unique=True)
|
||||||
password_hash = db.Column(db.Unicode)
|
password_hash = db.Column(db.Unicode)
|
||||||
@ -213,7 +213,7 @@ class UserSSO(db.Model, ModelController):
|
|||||||
otp_secret = db.Column(db.String(16))
|
otp_secret = db.Column(db.String(16))
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(UserSSO, self).__init__(**kwargs)
|
super(UserS, self).__init__(**kwargs)
|
||||||
if self.otp_secret is None:
|
if self.otp_secret is None:
|
||||||
# generate a random secret
|
# generate a random secret
|
||||||
self.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8')
|
self.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8')
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
def camel_case_to_snake_case(name):
|
def camel_case_to_snake_case(name):
|
||||||
@ -17,4 +19,11 @@ def snake_case_to_camel_case(name):
|
|||||||
:param name: the name to be converted
|
:param name: the name to be converted
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
return ''.join(x.title() for x in name.split('_'))
|
return ''.join(x.title() for x in name.split('_'))
|
||||||
|
|
||||||
|
|
||||||
|
def random_string_generator(str_size=30, allowed_chars=None):
|
||||||
|
if not allowed_chars:
|
||||||
|
allowed_chars = string.ascii_letters + string.digits
|
||||||
|
return ''.join(random.choice(allowed_chars) for _ in range(str_size))
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from flask import send_from_directory, redirect, request, url_for
|
from flask import send_from_directory, redirect, request, url_for, session, jsonify
|
||||||
|
|
||||||
|
from oshipka.util.strings import random_string_generator
|
||||||
from oshipka.webapp import oshipka_bp
|
from oshipka.webapp import oshipka_bp
|
||||||
from config import MEDIA_DIR, APP_BASE_URL
|
from config import MEDIA_DIR, APP_BASE_URL
|
||||||
from sensitive import SSO_CLIENT_ID, SSO_CLIENT_SECRET
|
from sensitive import SSO_CLIENT_ID, SSO_CLIENT_SECRET
|
||||||
@ -15,37 +16,56 @@ def get_media(filepath):
|
|||||||
|
|
||||||
|
|
||||||
SSO_BASE_URL = 'http://localhost:5008'
|
SSO_BASE_URL = 'http://localhost:5008'
|
||||||
|
SSO_AUTH_URL = '/oidc/auth'
|
||||||
|
SSO_TOKEN_URL = '/oidc/token'
|
||||||
|
SSO_USERINFO_URL = "/endpoints/userinfo"
|
||||||
|
|
||||||
|
|
||||||
@oshipka_bp.route('/sso')
|
@oshipka_bp.route('/sso')
|
||||||
def sso():
|
def sso():
|
||||||
callback_url = APP_BASE_URL + url_for('oshipka_bp.oidc_code')
|
callback_url = APP_BASE_URL + url_for('oshipka_bp.oidc_callback')
|
||||||
return redirect(SSO_BASE_URL + '/authenticate?callback={}&client_id={}'.format(
|
state = random_string_generator()
|
||||||
urllib.parse.quote(callback_url),
|
session['oidc_state'] = state
|
||||||
SSO_CLIENT_ID,
|
params = urllib.parse.urlencode({
|
||||||
))
|
'redirect_uri': callback_url,
|
||||||
|
'client_id': SSO_CLIENT_ID,
|
||||||
|
'state': state,
|
||||||
|
'scope': 'openid',
|
||||||
|
'response_type': 'code',
|
||||||
|
'nonce': random_string_generator(),
|
||||||
|
})
|
||||||
|
return redirect(SSO_BASE_URL + SSO_AUTH_URL + '?' + params)
|
||||||
|
|
||||||
|
|
||||||
@oshipka_bp.route('/oidc/code')
|
@oshipka_bp.route('/oidc/callback')
|
||||||
def oidc_code():
|
def oidc_callback():
|
||||||
|
error = request.args.get('error')
|
||||||
|
if error:
|
||||||
|
return jsonify({"error": "from auth server: {}".format(error)}), 400
|
||||||
|
state = request.args.get('state')
|
||||||
|
session_state = session['oidc_state']
|
||||||
|
if state != session_state:
|
||||||
|
return jsonify({"error": "state is different from session state"}), 400
|
||||||
code = request.args.get('code')
|
code = request.args.get('code')
|
||||||
# TODO : client_id and client_secret are passed in Authorization header
|
response = requests.post(
|
||||||
# https://connect2id.com/learn/openid-connect
|
SSO_BASE_URL + SSO_TOKEN_URL,
|
||||||
response = requests.get(
|
data={
|
||||||
SSO_BASE_URL + "/oidc/token",
|
|
||||||
params={
|
|
||||||
'code': code,
|
'code': code,
|
||||||
'client_id': SSO_CLIENT_ID,
|
'client_id': SSO_CLIENT_ID,
|
||||||
'client_secret': SSO_CLIENT_SECRET,
|
'client_secret': SSO_CLIENT_SECRET,
|
||||||
|
'grant_type': 'authorization_code'
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
response_json = response.json()
|
response_json = response.json()
|
||||||
access_token = response_json.get('access_token')
|
access_token = response_json.get('access_token')
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
SSO_BASE_URL + "/endpoints/user",
|
SSO_BASE_URL + SSO_USERINFO_URL,
|
||||||
headers={
|
headers={
|
||||||
'Authorization': "Bearer {}".format(access_token)
|
'Authorization': "Bearer {}".format(access_token)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
return 'got code for userinfo: {}'.format(response.status_code)
|
||||||
return 'got response for token: {}'.format(response.status_code)
|
return 'got response for token: {}'.format(response.status_code)
|
||||||
|
Loading…
Reference in New Issue
Block a user