Skip to content
Snippets Groups Projects
Commit 6948ddca authored by Julian's avatar Julian
Browse files

Fix "Migrate OAuth2 and API clients to database" (again)

The original change completely broke single logout support.

The migration now uses the correct hashing algorithm (unsalted SHA512 instead
of salted SHA512) for OAuth2/API secrets/passwords.
parent a97358ed
No related branches found
No related tags found
No related merge requests found
......@@ -19,12 +19,9 @@ down_revision = '09d2edcaf0cc'
branch_labels = None
depends_on = None
def hash_ssha512(password):
salt = secrets.token_bytes(8)
ctx = hashlib.new('sha512')
ctx.update(password.encode())
ctx.update(salt)
return '{ssha512}' + base64.b64encode(ctx.digest() + salt).decode()
def hash_sha512(password):
ctx = hashlib.new('sha512', password.encode())
return '{sha512}' + base64.b64encode(ctx.digest()).decode()
def upgrade():
used_service_names = set()
......@@ -129,7 +126,7 @@ def upgrade():
sa.UniqueConstraint('auth_username', name=op.f('uq_api_client_auth_username'))
)
for service_name, auth_username, auth_password, perm_users, perm_checkpassword, perm_mail_aliases in api_clients:
op.execute(api_client_table.insert().values(service_id=sa.select([service_table.c.id]).where(service_table.c.name==service_name).as_scalar(), auth_username=auth_username, auth_password=hash_ssha512(auth_password), perm_users=perm_users, perm_checkpassword=perm_checkpassword, perm_mail_aliases=perm_mail_aliases))
op.execute(api_client_table.insert().values(service_id=sa.select([service_table.c.id]).where(service_table.c.name==service_name).as_scalar(), auth_username=auth_username, auth_password=hash_sha512(auth_password), perm_users=perm_users, perm_checkpassword=perm_checkpassword, perm_mail_aliases=perm_mail_aliases))
oauth2client_table = op.create_table('oauth2client',
sa.Column('db_id', sa.Integer(), autoincrement=True, nullable=False),
......@@ -156,7 +153,7 @@ def upgrade():
sa.PrimaryKeyConstraint('id', name=op.f('pk_oauth2redirect_uri'))
)
for service_name, client_id, client_secret, redirect_uris, logout_uris in oauth2_clients:
op.execute(oauth2client_table.insert().values(service_id=sa.select([service_table.c.id]).where(service_table.c.name==service_name).as_scalar(), client_id=client_id, client_secret=hash_ssha512(client_secret)))
op.execute(oauth2client_table.insert().values(service_id=sa.select([service_table.c.id]).where(service_table.c.name==service_name).as_scalar(), client_id=client_id, client_secret=hash_sha512(client_secret)))
for method, uri, in logout_uris:
op.execute(oauth2logout_uri_table.insert().values(client_db_id=sa.select([oauth2client_table.c.db_id]).where(oauth2client_table.c.client_id==client_id).as_scalar(), method=method, uri=uri))
for uri in redirect_uris:
......
import datetime
import json
from sqlalchemy import Column, Integer, String, DateTime, Text, ForeignKey
from sqlalchemy.orm import relationship
......@@ -41,6 +42,10 @@ class OAuth2Client(db.Model):
def access_allowed(self, user):
return self.service.has_access(user)
@property
def logout_uris_json(self):
return json.dumps([[item.method, item.uri] for item in self.logout_uris])
class OAuth2RedirectURI(db.Model):
__tablename__ = 'oauth2redirect_uri'
id = Column(Integer, primary_key=True, autoincrement=True)
......
......@@ -11,9 +11,9 @@
</noscript>
<p>{{_('While you successfully logged out of the Single-Sign-On service, you may still be logged in on these services:')}}</p>
<ul>
{% for client in clients if client.logout_urls %}
<li class="client" data-urls='{{ client.logout_urls|tojson }}'>
{{ client.client_id }}
{% for client in clients if client.logout_uris %}
<li class="client" data-urls='{{ client.logout_uris_json }}'>
{{ client.service.name }}
<span class="status-active spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
<i class="status-success fas fa-check d-none"></i>
<i class="status-failed fas fa-exclamation d-none"></i>
......@@ -53,7 +53,6 @@ function logout_services() {
});
});
p = p.then(function () {
console.log('done', elem);
elem.find('.status-active').addClass('d-none');
elem.find('.status-success').removeClass('d-none');
elem.removeClass('client');
......@@ -61,13 +60,11 @@ function logout_services() {
.catch(function (err) {
elem.find('.status-active').addClass('d-none');
elem.find('.status-failed').removeClass('d-none');
console.log(err);
throw err;
});
all_promises.push(p);
});
Promise.allSettled(all_promises).then(function (results) {
console.log(results);
for (result of results) {
if (result.status == 'rejected')
throw result.reason;
......
......@@ -249,5 +249,5 @@ def logout():
if not request.values.get('client_ids'):
return secure_local_redirect(request.values.get('ref', '/'))
client_ids = request.values['client_ids'].split(',')
clients = [OAuth2Client.query.filter_by(name=client_id).one() for client_id in client_ids]
clients = [OAuth2Client.query.filter_by(client_id=client_id).one() for client_id in client_ids]
return render_template('oauth2/logout.html', clients=clients)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment