Add experimental oidc dashboard view

This commit is contained in:
Johannes Zellner
2023-03-21 17:40:32 +01:00
parent b78c773bc6
commit 14bcfbeeb2
5 changed files with 299 additions and 1 deletions

View File

@@ -0,0 +1,140 @@
<!-- Modal client add -->
<div class="modal fade" id="clientAddModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Add client</h4>
</div>
<div class="modal-body">
Add new OpenID connect client settings.
<br/>
<br/>
<form name="clientAddForm" role="form" novalidate ng-submit="clientAdd.submit()" autocomplete="off">
<div class="form-group" ng-class="{ 'has-error': clientAdd.error.id }">
<label class="control-label" for="clientId">Client ID</label>
<input type="text" id="clientId" class="form-control" name="clientId" ng-model="clientAdd.id" autofocus required/>
<div class="control-label" ng-show="clientAdd.error.id">
<small>{{ clientAdd.error.id }}</small>
</div>
</div>
<div class="form-group">
<label class="control-label" for="clientSecret">Client Secret</label>
<input type="text" id="clientSecret" class="form-control" name="clientSecret" ng-model="clientAdd.secret" required/>
</div>
<div class="form-group">
<label class="control-label" for="loginRedirectUri">Login callback Url</label>
<input type="url" id="loginRedirectUri" class="form-control" name="loginRedirectUri" ng-model="clientAdd.loginRedirectUri" required/>
</div>
<div class="form-group">
<label class="control-label" for="logoutRedirectUri">Logout callback Url (optional)</label>
<input type="url" id="logoutRedirectUri" class="form-control" name="logoutRedirectUri" ng-model="clientAdd.logoutRedirectUri"/>
</div>
<input class="ng-hide" type="submit" ng-disabled="clientAddForm.$invalid"/>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'main.dialog.close' | tr }}</button>
<button type="button" class="btn btn-success" ng-click="clientAdd.submit()" ng-disabled="clientAddForm.$invalid || clientAdd.busy">
<i class="fa fa-circle-notch fa-spin" ng-show="clientAdd.busy"></i> Create
</button>
</div>
</div>
</div>
</div>
<!-- Modal client delete -->
<div class="modal fade" id="clientDeleteModal" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Really delete client {{ deleteClient.id }}?</h4>
</div>
<div class="modal-body">
<p>This will disconnect all external OpenID apps from this Cloudron using this client ID.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'main.dialog.cancel' | tr }}</button>
<button type="button" class="btn btn-danger" ng-click="deleteClient.submit()" ng-disabled="deleteClient.busy"><i class="fa fa-circle-notch fa-spin" ng-show="deleteClient.busy"></i> Delete</button>
</div>
</div>
</div>
</div>
<div class="content">
<div class="text-left">
<h1>OpenID Provider</h1>
</div>
<div class="card">
<div class="grid-item-top">
<div class="row">
<div class="col-md-12">
<table width="100%">
<tr>
<td class="text-muted" style="vertical-align: top;">Discovery URL</td>
<td class="text-right" style="vertical-align: top;">https://{{ config.adminDomain }}/.well-known/openid-configuration</td>
</tr>
<tr>
<td class="text-muted" style="vertical-align: top;">Auth Endpoint</td>
<td class="text-right" style="vertical-align: top;">https://{{ config.adminFqdn }}/openid/auth</td>
</tr>
<tr>
<td class="text-muted" style="vertical-align: top;">Token Endpoint</td>
<td class="text-right" style="vertical-align: top;">https://{{ config.adminFqdn }}/openid/token</td>
</tr>
<tr>
<td class="text-muted" style="vertical-align: top;">Keys Endpoint</td>
<td class="text-right" style="vertical-align: top;">https://{{ config.adminFqdn }}/openid/jwks</td>
</tr>
<tr>
<td class="text-muted" style="vertical-align: top;">Profile Endpoint</td>
<td class="text-right" style="vertical-align: top;">https://{{ config.adminFqdn }}/openid/me</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<br>
<div class="text-left">
<h3>Clients <button class="btn btn-primary btn-sm pull-right" ng-click="clientAdd.show()"><i class="fa fa-plus"></i> New client</button></h3>
</div>
<div class="card">
<div class="grid-item-top">
<div class="row">
<div class="col-xs-12">
<table class="table table-hover">
<thead>
<tr>
<th style="width: 45%">Client ID</th>
<th style="width: 45%">Client Secret</th>
<th style="width: 10%" class="text-right">{{ 'main.actions' | tr }}</th>
</tr>
</thead>
<tbody>
<tr ng-show="clients.length === 0">
<td colspan="3" class="text-center">No clients yet</td>
</tr>
<tr ng-repeat="client in clients">
<td class="text-left elide-table-cell">
{{ client.id }}
</td>
<td class="text-left elide-table-cell">
{{ client.secret }}
</td>
<td class="text-right no-wrap" style="vertical-align: bottom">
<button class="btn btn-xs btn-danger pull-right" ng-click="deleteClient.show(client.id)" uib-tooltip="Delete"><i class="far fa-trash-alt"></i></button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>

104
dashboard/src/views/oidc.js Normal file
View File

@@ -0,0 +1,104 @@
'use strict';
/* global angular */
/* global $ */
angular.module('Application').controller('OidcController', ['$scope', '$location', 'Client', function ($scope, $location, Client) {
Client.onReady(function () { if (!Client.getUserInfo().isAtLeastAdmin) $location.path('/'); });
$scope.user = Client.getUserInfo();
$scope.config = Client.getConfig();
$scope.clients = [];
$scope.refreshClients = function () {
Client.getOidcClients(function (error, result) {
if (error) return console.error('Failed to load oidc clients', error);
$scope.clients = result;
});
};
$scope.clientAdd = {
busy: false,
error: {},
id: '',
secret: '',
loginRedirectUri: '',
logoutRedirectUri: '',
show: function () {
$scope.clientAdd.id = '';
$scope.clientAdd.secret = '';
$scope.clientAdd.loginRedirectUri = '';
$scope.clientAdd.logoutRedirectUri = '';
$scope.clientAdd.busy = false;
$scope.clientAdd.error = null;
$scope.clientAddForm.$setPristine();
$('#clientAddModal').modal('show');
},
submit: function () {
$scope.clientAdd.busy = true;
$scope.clientAdd.error = {};
Client.addOidcClient($scope.clientAdd.id, $scope.clientAdd.secret, $scope.clientAdd.loginRedirectUri, $scope.clientAdd.logoutRedirectUri, function (error) {
if (error) {
if (error.statusCode === 409) {
$scope.clientAdd.error.id = 'Client ID already exists';
$('#clientId').focus();
} else {
console.error('Unable to add openid client.', error);
}
$scope.clientAdd.busy = false;
return;
}
$scope.refreshClients();
$scope.clientAdd.busy = false;
$('#clientAddModal').modal('hide');
});
}
};
$scope.deleteClient = {
busy: false,
error: {},
id: '',
show: function (clientId) {
$scope.deleteClient.busy = false;
$scope.deleteClient.id = clientId;
$('#clientDeleteModal').modal('show');
},
submit: function () {
Client.delOidcClient($scope.deleteClient.id, function (error) {
$scope.deleteClient.busy = false;
if (error) return console.error('Failed to delete openid client', error);
$scope.refreshClients();
$('#clientDeleteModal').modal('hide');
});
}
};
Client.onReady(function () {
$scope.refreshClients();
});
// setup all the dialog focus handling
['clientAddModal', 'clientEditModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find('[autofocus]:first').focus();
});
});
$('.modal-backdrop').remove();
}]);