Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(GDB-11339): Manage the graphql roles #1809

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
43 changes: 43 additions & 0 deletions src/css/user.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
.wb-user .auth-column-label {
margin-right: 4px;
}

.wb-user .repository-column {
width: 50%;
}

.wb-user .read-column {
width: 15%;
}

.wb-user .write-column {
width: 15%;
}

.wb-user .write-column,
.wb-user .write-rights,
.wb-user .write-any {
border-right: 1px solid #eceeef;
}

.wb-user .graphql-column {
width: 15%;
}
.wb-user .table-fixed {
table-layout: fixed;
width: 100%;
}

.wb-user .bordered-table {
border: 1px solid #eceeef;
border-collapse: collapse;
width: 100%;
}

.wb-user .graphql-icon {
margin-left: 4px;
}

.wb-user .repository-name {
word-wrap: break-word;
}
11 changes: 9 additions & 2 deletions src/i18n/locale-en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1276,8 +1276,12 @@
"security.user.role.too.short": "Must be at least 2 symbols long",
"security.no.active.location": "There is no active location.",
"security.repository.title": "Repository",
"security.tooltip.read": "Read",
"security.tooltip.write": "Write",
"security.tooltip.read": "Read rights",
"security.tooltip.write": "Write rights",
"security.tooltip.graphql": "GraphQL only rights",
"security.label.read": "Read",
"security.label.write": "Write",
"security.label.graphql": "GraphQL only",
"security.user.may": "User may:",
"security.use.gdb": "Use GraphDB",
"security.grant.read.access": "Be granted read access to a repository",
Expand Down Expand Up @@ -1336,6 +1340,8 @@
"security.has.read.access": "Has read access",
"security.no.read.access": "Does not have read access",
"security.has.write.access": "Has write access",
"security.has.mutation_rights": "Has mutation rights",
"security.no.mutation_rights": "Does not have mutation rights",
"security.no.write.access": "Does not have write access",
"security.unrestricted": "Unrestricted",
"security.edit.user.tooltip": "Edit user",
Expand Down Expand Up @@ -2125,6 +2131,7 @@
"repo.choose.location.warning": "select a location first",
"repo.properties": "Repository properties",
"repo.id.label": "Repository ID*",
"repo.local": "Local",
"edit.repo.id.tooltip": "Edit repository id",
"edit.repo.id.cannot_edit_in_cluster.tooltip": "Cannot rename repository while in cluster.",
"invalid.repo.name.error": "Repository name can contain only letters (a-z, A-Z), numbers (0-9), \"-\" and \"_\"",
Expand Down
11 changes: 9 additions & 2 deletions src/i18n/locale-fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1276,8 +1276,12 @@
"security.user.role.too.short": "Doit contenir au moins 2 symboles",
"security.no.active.location": "Il n'y a pas de dépôt actif.",
"security.repository.title": "Dépôt",
"security.tooltip.read": "Lire",
"security.tooltip.write": "Ecriture",
"security.tooltip.read": "Droits de lecture",
"security.tooltip.write": "Droits d'écriture",
"security.tooltip.graphql": "Droits GraphQL uniquement",
"security.label.read": "Lire",
"security.label.write": "Ecriture",
"security.label.graphql": "GraphQL uniquement",
"security.user.may": "L'utilisateur peut :",
"security.use.gdb": "Utiliser GraphDB",
"security.grant.read.access": "Avoir un accès en lecture à un dépôt",
Expand Down Expand Up @@ -1336,6 +1340,8 @@
"security.has.read.access": "A accès en lecture",
"security.no.read.access": "N'a pas l'accès en lecture",
"security.has.write.access": "Accès en écriture",
"security.has.mutation_rights": "A des droits de mutation",
"security.no.mutation_rights": "N'a pas de droits de mutation",
"security.no.write.access": "N'a pas d'accès en écriture",
"security.unrestricted": "Sans restriction",
"security.edit.user.tooltip": "Modifier un utilisateur",
Expand Down Expand Up @@ -2125,6 +2131,7 @@
"repo.choose.location.warning": "Veuillez d'abord sélectionner un lieu",
"repo.properties": "Propriétés du dépôt",
"repo.id.label": "ID du dépôt*",
"repo.local": "Local",
"edit.repo.id.tooltip": "Modifier l'ID du dépôt",
"edit.repo.id.cannot_edit_in_cluster.tooltip": "Impossible de renommer le référentiel en mode cluster.",
"invalid.repo.name.error": "Le nom du dépôt ne peut contenir que des lettres (a-z, A-Z), des chiffres (0-9), \"-\" et \"_\".",
Expand Down
9 changes: 5 additions & 4 deletions src/js/angular/controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,13 @@ function mainCtrl($scope, $menuItems, $jwtAuth, $http, toastr, $location, $repos
return $repositories.getRepositories();
};

$scope.getReadableRepositories = function () {
return $repositories.getReadableRepositories();
$scope.getReadableRepositories = function (qraphql = false) {
return $repositories.getReadableRepositories(qraphql);
};

$scope.getWritableRepositories = function () {
return $repositories.getWritableRepositories();

$scope.getWritableRepositories = function (qraphql = false) {
return $repositories.getWritableRepositories(qraphql);
};

$scope.getActiveRepository = function () {
Expand Down
61 changes: 33 additions & 28 deletions src/js/angular/core/services/jwt-auth.service.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import 'angular/core/services';
import 'angular/core/services/openid-auth.service.js';
import 'angular/rest/security.rest.service';
import 'angular/core/services/security.service';
import {UserRole} from 'angular/utils/user-utils';

angular.module('graphdb.framework.core.services.jwtauth', [
'toastr',
'graphdb.framework.rest.security.service',
'graphdb.framework.core.services.security-service',
'graphdb.framework.core.services.openIDService'
])
.service('$jwtAuth', ['$http', 'toastr', '$location', '$rootScope', 'SecurityRestService', '$openIDAuth', '$translate', '$q', 'AuthTokenService', 'LSKeys', 'LocalStorageAdapter',
function ($http, toastr, $location, $rootScope, SecurityRestService, $openIDAuth, $translate, $q, AuthTokenService, LSKeys, LocalStorageAdapter) {
.service('$jwtAuth', ['$http', 'toastr', '$location', '$rootScope', 'SecurityService', '$openIDAuth', '$translate', '$q', 'AuthTokenService', 'LSKeys', 'LocalStorageAdapter',
function ($http, toastr, $location, $rootScope, SecurityService, $openIDAuth, $translate, $q, AuthTokenService, LSKeys, LocalStorageAdapter) {
const jwtAuth = this;

$rootScope.deniedPermissions = {};
Expand Down Expand Up @@ -88,8 +88,7 @@ angular.module('graphdb.framework.core.services.jwtauth', [
* @param {boolean} justLoggedIn Indicates that the user just logged in.
*/
this.getAuthenticatedUserFromBackend = function(noFreeAccessFallback, justLoggedIn) {
SecurityRestService.getAuthenticatedUser().
success(function(data, status, headers) {
SecurityService.getAuthenticatedUser().then(function(data) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beware of these changes. There were few places where the success/error handlers were left intentionally due to sertain reasons that I can't recall at the moment but if possible, I'd prefer if we don't switch them here, now

const token = AuthTokenService.getAuthToken();
if (token && token.startsWith('GDB')) {
// There is a previous authentication via JWT, it's still valid
Expand All @@ -108,7 +107,7 @@ angular.module('graphdb.framework.core.services.jwtauth', [
that.authenticate(data, ''); // this will emit securityInit
// console.log('external authentication ok');
}
}).error(function () {
}).catch(function () {
if (noFreeAccessFallback || !that.freeAccess) {
$rootScope.redirectToLogin(false, justLoggedIn);
} else {
Expand All @@ -124,7 +123,7 @@ angular.module('graphdb.framework.core.services.jwtauth', [
this.initSecurity = function () {
this.securityInitialized = false;

SecurityRestService.getSecurityConfig().then(function (res) {
SecurityService.getSecurityConfig().then(function (res) {
that.securityEnabled = res.data.enabled;
that.externalAuth = res.data.hasExternalAuth;
that.authImplementation = res.data.authImplementation;
Expand Down Expand Up @@ -187,8 +186,8 @@ angular.module('graphdb.framework.core.services.jwtauth', [
$rootScope.$broadcast('securityInit', that.securityEnabled, true, that.hasOverrideAuth);

} else {
return SecurityRestService.getAdminUser().then(function (res) {
that.principal = {username: 'admin', appSettings: res.data.appSettings, authorities: res.data.grantedAuthorities};
return SecurityService.getAdminUser().then(function (res) {
that.principal = {username: 'admin', appSettings: res.appSettings, authorities: res.grantedAuthorities, grantedAuthoritiesUiModel: res.grantedAuthoritiesUiModel};
$rootScope.$broadcast('securityInit', that.securityEnabled, true, that.hasOverrideAuth);
});
}
Expand Down Expand Up @@ -236,7 +235,7 @@ angular.module('graphdb.framework.core.services.jwtauth', [

this.toggleSecurity = function (enabled) {
if (enabled !== this.securityEnabled) {
return SecurityRestService.toggleSecurity(enabled)
return SecurityService.toggleSecurity(enabled)
.then(function () {
toastr.success($translate.instant('jwt.auth.security.status', {status: ($translate.instant(enabled ? 'enabled.status' : 'disabled.status'))}));
AuthTokenService.clearAuthToken();
Expand All @@ -257,7 +256,7 @@ angular.module('graphdb.framework.core.services.jwtauth', [
} else {
this.freeAccessPrincipal = undefined;
}
SecurityRestService.setFreeAccess({
SecurityService.setFreeAccess({
enabled: enabled ? 'true' : 'false',
authorities: authorities,
appSettings: appSettings
Expand Down Expand Up @@ -398,7 +397,7 @@ angular.module('graphdb.framework.core.services.jwtauth', [
return this.isAdmin() || this.isRepoManager();
};

this.canWriteRepo = function (repo) {
this.canWriteRepo = function (repo, graphql = false) {
if (!repo) {
return false;
}
Expand All @@ -410,13 +409,13 @@ angular.module('graphdb.framework.core.services.jwtauth', [
} else if (this.hasAdminRole()) {
return true;
}
return this.checkRights(repo, 'WRITE');
return this.checkRights(repo, 'WRITE', graphql);
} else {
return true;
}
};

this.canReadRepo = function (repo) {
this.canReadRepo = function (repo, graphql = false) {
if (!repo) {
return false;
}
Expand All @@ -428,27 +427,33 @@ angular.module('graphdb.framework.core.services.jwtauth', [
} else if (this.hasAdminRole()) {
return true;
}
return this.checkRights(repo, 'READ');
return this.checkRights(repo, 'READ', graphql);
} else {
return true;
}
};

this.checkRights = function (repo, action) {
if (repo) {
for (let i = 0; i < this.principal.authorities.length; i++) {
const authRole = this.principal.authorities[i];
const parts = authRole.split('_', 2);
const repoPart = authRole.slice(parts[0].length + parts[1].length + 2);
const repoId = repo.location ? `${repo.id}@${repo.location}` : repo.id;
if (parts[0] === action && (repoId === repoPart || repo.id !== 'SYSTEM' && repoPart === '*')) {
return true;
}

this.checkRights = function (repo, action, graphql = false) {
if (!repo) {
return false;
}

const repoId = repo.location ? `${repo.id}@${repo.location}` : repo.id;
const overCurrentRepo = `${action}_REPO_${repoId}`;
const overAllRepos = `${action}_REPO_*`;

if (graphql) {
const overCurrentRepoGraphql = `${overCurrentRepo}:GRAPHQL`;
const overAllReposGraphql = `${overAllRepos}:GRAPHQL`;
if (repo.id !== 'SYSTEM' && (this.principal.authorities.indexOf(overCurrentRepoGraphql) > -1 || this.principal.authorities.indexOf(overAllReposGraphql) > -1)) {
return true;
}
}
return false;

return repo.id !== 'SYSTEM' && (this.principal.authorities.indexOf(overCurrentRepo) > -1 || this.principal.authorities.indexOf(overAllRepos) > -1);
};


this.updateUserData = (data) => SecurityRestService.updateUserData(data);
this.updateUserData = (data) => SecurityService.updateUserData(data);
}]);
4 changes: 2 additions & 2 deletions src/js/angular/core/services/repositories.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ repositories.service('$repositories', ['toastr', '$rootScope', '$timeout', '$loc
return this.getRepositories().find((repository) => repository.id === repositoryId);
};

this.getReadableRepositories = function () {
this.getReadableRepositories = function (graphql = false) {
return _.filter(this.getRepositories(), function (repo) {
return $jwtAuth.canReadRepo(repo);
return $jwtAuth.canReadRepo(repo, graphql);
});
};

Expand Down
Loading