Introducing new PKI management
This commit is contained in:
parent
69640506d0
commit
0259ae8f94
19 changed files with 857 additions and 53 deletions
|
|
@ -29,6 +29,7 @@
|
|||
<div class="collapse navbar-collapse" id="adminMenu">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item"><a class="nav-link" href="/teams">Équipes</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/pki">PKI</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/themes">Thèmes</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/exercices">Exercices</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/files">Fichiers</a></li>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ angular.module("FICApp", ["ngRoute", "ngResource", "ngSanitize"])
|
|||
controller: "SettingsController",
|
||||
templateUrl: "views/settings.html"
|
||||
})
|
||||
.when("/pki", {
|
||||
controller: "PKIController",
|
||||
templateUrl: "views/pki.html"
|
||||
})
|
||||
.when("/exercices", {
|
||||
controller: "AllExercicesListController",
|
||||
templateUrl: "views/exercice-list.html"
|
||||
|
|
@ -132,6 +136,14 @@ angular.module("FICApp")
|
|||
'update': {method: 'PUT'},
|
||||
})
|
||||
})
|
||||
.factory("Certificate", function($resource) {
|
||||
return $resource("/api/certs/:serial", { serial: '@id' }, {
|
||||
'update': {method: 'PUT'},
|
||||
})
|
||||
})
|
||||
.factory("CACertificate", function($resource) {
|
||||
return $resource("/api/ca/:serial", { serial: '@id' })
|
||||
})
|
||||
.factory("File", function($resource) {
|
||||
return $resource("/api/files/:fileId", { fileId: '@id' })
|
||||
})
|
||||
|
|
@ -153,6 +165,9 @@ angular.module("FICApp")
|
|||
'update': {method: 'PUT'},
|
||||
})
|
||||
})
|
||||
.factory("TeamCertificate", function($resource) {
|
||||
return $resource("/api/teams/:teamId/certificates", { teamId: '@id' })
|
||||
})
|
||||
.factory("TeamMember", function($resource) {
|
||||
return $resource("/api/teams/:teamId/members", { teamId: '@id' }, {
|
||||
'save': {method: 'PUT'},
|
||||
|
|
@ -451,6 +466,56 @@ angular.module("FICApp")
|
|||
};
|
||||
})
|
||||
|
||||
.controller("PKIController", function($scope, $rootScope, Certificate, CACertificate, Team, $location, $http) {
|
||||
$scope.teams = Team.query();
|
||||
$scope.certificates = Certificate.query();
|
||||
$scope.ca = CACertificate.get();
|
||||
|
||||
$scope.revoke = function() {
|
||||
var targetserial = $("#revokeModal").data("certificate");
|
||||
if (targetserial) {
|
||||
Certificate.delete({ serial: targetserial }).$promise.then(
|
||||
function() {
|
||||
$('#revokeModal').modal('hide');
|
||||
$scope.certificates = Certificate.query();
|
||||
}, function(response) {
|
||||
$rootScope.newBox('danger', 'An error occurs when trying to associate certificate:', response.data);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.associate = function() {
|
||||
var targetserial = $("#associationModal").data("certificate");
|
||||
if (!targetserial) return;
|
||||
Certificate.update({ serial: targetserial }, { id_team: $scope.selectedTeam }).$promise.then(
|
||||
function() {
|
||||
$('#associationModal').modal('hide');
|
||||
$scope.certificates = Certificate.query();
|
||||
$scope.selectedTeam = null;
|
||||
}, function(response) {
|
||||
$rootScope.newBox('danger', 'An error occurs when trying to associate certificate:', response.data);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.generateCA = function() {
|
||||
$http.post("/api/ca/new").then(function() {
|
||||
$scope.ca = CACertificate.get();
|
||||
}, function(response) {
|
||||
$rootScope.newBox('danger', 'An error occurs when generating CA:', response.data);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.generateCert = function() {
|
||||
$http.post("/api/certs").then(function() {
|
||||
$scope.certificates = Certificate.query();
|
||||
}, function(response) {
|
||||
$rootScope.newBox('danger', 'An error occurs when generating certificate:', response.data);
|
||||
});
|
||||
};
|
||||
})
|
||||
|
||||
.controller("PublicController", function($scope, $rootScope, $routeParams, $location, Scene, Theme, Teams, Exercice) {
|
||||
$scope.screens = [0,1,2,3,4,5,6,7,8,9];
|
||||
$scope.screenid = $routeParams.screenId;
|
||||
|
|
@ -1068,47 +1133,26 @@ angular.module("FICApp")
|
|||
}
|
||||
}
|
||||
})
|
||||
.controller("TeamController", function($scope, $rootScope, $location, Team, TeamMember, $routeParams, $http) {
|
||||
.controller("TeamController", function($scope, $rootScope, $location, Team, TeamMember, TeamCertificate, $routeParams, $http) {
|
||||
if ($scope.team && $scope.team.id)
|
||||
$routeParams.teamId = $scope.team.id;
|
||||
$scope.team = Team.get({ teamId: $routeParams.teamId });
|
||||
$scope.fields = ["name", "color"];
|
||||
|
||||
$scope.hasCertificate = false;
|
||||
$http({
|
||||
url: "/api/teams/" + Math.floor($routeParams.teamId) + "/certificate.p12",
|
||||
method: "HEAD",
|
||||
transformResponse: null
|
||||
}).then(function(response) {
|
||||
$scope.hasCertificate = true;
|
||||
}, function(response) {
|
||||
$scope.hasCertificate = false;
|
||||
});
|
||||
$scope.certificates = TeamCertificate.query({ teamId: $routeParams.teamId });
|
||||
|
||||
$scope.generateCertificate = function() {
|
||||
$scope.dissociateCertificate = function(certificate) {
|
||||
$http({
|
||||
url: "/api/teams/" + Math.floor($routeParams.teamId) + "/certificate/generate",
|
||||
method: "POST",
|
||||
transformResponse: null
|
||||
url: "/api/certs/" + certificate.id,
|
||||
method: "PUT",
|
||||
data: {
|
||||
id_team: null
|
||||
}
|
||||
}).then(function(response) {
|
||||
$scope.hasCertificate = true;
|
||||
$rootScope.newBox('success', 'Team certificate successfully generated!');
|
||||
$scope.certificates = TeamCertificate.query({ teamId: $routeParams.teamId });
|
||||
$rootScope.newBox('success', 'Certificate successfully dissociated!');
|
||||
}, function(response) {
|
||||
$rootScope.newBox('danger', 'An error occurs when generating certiticate:', response.data);
|
||||
});
|
||||
}
|
||||
$scope.revokeCertificate = function() {
|
||||
if (!confirm("Are you sure you want to revoke this certificate?"))
|
||||
return false;
|
||||
|
||||
$http({
|
||||
url: "/api/teams/" + Math.floor($routeParams.teamId) + "/certificate.p12",
|
||||
method: "DELETE",
|
||||
transformResponse: null
|
||||
}).then(function(response) {
|
||||
$scope.hasCertificate = false;
|
||||
}, function(response) {
|
||||
$rootScope.newBox('danger', 'An error occurs when revoking the certiticate:', response.data);
|
||||
$rootScope.newBox('danger', 'An error occurs when dissociating certiticate:', response.data);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
126
admin/static/views/pki.html
Normal file
126
admin/static/views/pki.html
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<h2>
|
||||
Certificats clients
|
||||
<button ng-click="generateCert()" class="float-right btn btn-sm btn-primary" style="margin-right: 10px"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Générer un certificat</button>
|
||||
</h2>
|
||||
|
||||
<p><input type="search" class="form-control" placeholder="Search" ng-model="query" autofocus></p>
|
||||
<table class="table table-hover table-bordered table-striped table-sm">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Serial</th>
|
||||
<th>Date de création</th>
|
||||
<th>Équipe</th>
|
||||
<th>Révoqué ?</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="certificate in certificates | filter: query" ng-click="show(certificate.id)">
|
||||
<td>{{ certificate.id }}</td>
|
||||
<td>{{ certificate.creation }}</td>
|
||||
<td ng-if="certificate.id_team">
|
||||
<span ng-repeat="team in teams" ng-if="team.id == certificate.id_team">
|
||||
<a ng-href="teams/{{ team.id }}">{{ team.name }}</a>
|
||||
</span>
|
||||
</td>
|
||||
<td ng-if="!certificate.id_team">
|
||||
<button type="button" class="btn btn-sm btn-primary" data-toggle="modal" data-target="#associationModal" data-certificate="{{ certificate.id }}"><span class="glyphicon glyphicon-link" aria-hidden="true"></span> Associer</button>
|
||||
</td>
|
||||
<td>{{ certificate.revoked }}</td>
|
||||
<td>
|
||||
<a type="button" class="btn btn-sm btn-success" href="api/certs/{{ certificate.id }}" target="_self">Télécharger</a>
|
||||
<button type="button" class="btn btn-sm btn-danger" data-toggle="modal" data-target="#revokeModal" data-certificate="{{ certificate.id }}">Révoquer</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="modal fade" id="revokeModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Révocation d'un certificat</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>
|
||||
Êtes-vous sûr de vouloir révoquer le certificat ?
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
|
||||
<button type="button" class="btn btn-danger" ng-click="revoke()">Révoquer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#revokeModal').on('shown.bs.modal', function (event) {
|
||||
var button = $(event.relatedTarget);
|
||||
var serial = button.data('certificate');
|
||||
|
||||
var modal = $(this);
|
||||
modal.data('certificate', serial);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="modal fade" id="associationModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Associer le certificat à une équipe</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form ng-submit="associate()">
|
||||
<div class="modal-body row">
|
||||
<label for="tteam" class="col-md-auto col-form-label">Équipe</label>
|
||||
<div class="col-md-auto">
|
||||
<select class="custom-select custom-select-sm" id="tteam" ng-model="selectedTeam" ng-options="t.id as t.name for t in teams"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
|
||||
<button type="submit" class="btn btn-primary">Associer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#associationModal').on('shown.bs.modal', function (event) {
|
||||
$('#tteam').trigger('focus');
|
||||
|
||||
var button = $(event.relatedTarget);
|
||||
var serial = button.data('certificate');
|
||||
|
||||
var modal = $(this);
|
||||
modal.data('certificate', serial);
|
||||
});
|
||||
</script>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>
|
||||
Autorité de certification
|
||||
<span class="badge badge-success" ng-if="ca.version">Générée</span>
|
||||
<span class="badge badge-danger" ng-if="!ca.version">Introuvable</span>
|
||||
<button ng-click="generateCA()" class="float-right btn btn-sm btn-primary" ng-if="!ca.version"><span class="glyphicon glyphicon-certificate" aria-hidden="true"></span> Générer</button>
|
||||
</h2>
|
||||
|
||||
<div class="alert alert-info" ng-if="!ca.version">
|
||||
<strong>Aucune CA n'a été générée pour le moment.</strong>
|
||||
</div>
|
||||
|
||||
<dl ng-if="ca.version">
|
||||
<ng-repeat ng-repeat="(k, v) in ca">
|
||||
<dt>{{ k }}</dt>
|
||||
<dd ng-if="v.CommonName">/CN={{ v.CommonName }}/OU={{ v.OrganizationalUnit }}/O={{ v.Organization }}/L={{ v.Locality }}/P={{ v.Province }}/C={{ v.Country }}/</dd>
|
||||
<dd ng-if="!v.CommonName">{{ v }}</dd>
|
||||
</ng-repeat>
|
||||
</dl>
|
||||
|
|
@ -69,15 +69,30 @@
|
|||
<div class="card">
|
||||
<div class="card-header bg-primary text-light">
|
||||
<span class="glyphicon glyphicon-certificate" aria-hidden="true"></span>
|
||||
Certificate
|
||||
<span class="badge badge-success" ng-if="hasCertificate">Generated</span>
|
||||
<span class="badge badge-danger" ng-if="!hasCertificate">Not found</span>
|
||||
Certificates
|
||||
<span class="badge badge-success" ng-if="certificates.length">Generated</span>
|
||||
<span class="badge badge-danger" ng-if="!certificates.length">Not found</span>
|
||||
</div>
|
||||
<div class="card-body bg-light text-dark">
|
||||
<button ng-click="generateCertificate()" class="btn btn-success" ng-if="!hasCertificate">
|
||||
<span class="glyphicon glyphicon-certificate" aria-hidden="true"></span> Generate certificate</button>
|
||||
<button ng-click="revokeCertificate()" class="btn btn-danger" ng-if="hasCertificate">
|
||||
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> Revoke certificate</button>
|
||||
<dl class="dl-horizontal" ng-repeat="cert in certificates">
|
||||
<dt>
|
||||
Numéro de série
|
||||
<button type="button" class="btn btn-sm btn-primary float-right" ng-click="dissociateCertificate(cert)">Dissocier</button>
|
||||
</dt>
|
||||
<dd>
|
||||
{{ cert.id }}
|
||||
<span class="badge badge-danger" ng-if="cert.revoked">Révoqué</span>
|
||||
</dd>
|
||||
<dt>
|
||||
Date de création
|
||||
<a class="btn btn-sm btn-success float-right" href="../api/certs/{{ cert.id }}">Télécharger</a>
|
||||
</dt>
|
||||
<dd>{{ cert.creation }}</dd>
|
||||
<dt>Mot de passe</dt>
|
||||
<dd>{{ cert.password }}</dd>
|
||||
<dt ng-if="cert.revoked">Date de révocation</dt>
|
||||
<dd ng-if="cert.revoked">{{ cert.revoked }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Reference in a new issue