-{{'AUTHENTICATION.MFA_INFO'|translate}}{{mfaUrl}}
+
diff --git a/apps/user-profile/src/app/pages/settings-page/settings-authorization/settings-authentication.component.ts b/apps/user-profile/src/app/pages/settings-page/settings-authorization/settings-authentication.component.ts
index 3da975387..ca21cbf86 100644
--- a/apps/user-profile/src/app/pages/settings-page/settings-authorization/settings-authentication.component.ts
+++ b/apps/user-profile/src/app/pages/settings-page/settings-authorization/settings-authentication.component.ts
@@ -1,30 +1,40 @@
-import { Component, OnInit } from '@angular/core';
+import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { getDefaultDialogConfig } from '@perun-web-apps/perun/utils';
import { AddAuthImgDialogComponent } from '../../../components/dialogs/add-auth-img-dialog/add-auth-img-dialog.component';
import { Attribute, AttributesManagerService } from '@perun-web-apps/perun/openapi';
-import { StoreService } from '@perun-web-apps/perun/services';
+import { AuthService, StoreService } from '@perun-web-apps/perun/services';
import { RemoveStringValueDialogComponent } from '../../../components/dialogs/remove-string-value-dialog/remove-string-value-dialog.component';
import { TranslateService } from '@ngx-translate/core';
+import { OAuthService } from 'angular-oauth2-oidc';
+import { MatSlideToggle } from '@angular/material/slide-toggle';
@Component({
selector: 'perun-web-apps-settings-authentication',
templateUrl: './settings-authentication.component.html',
styleUrls: ['./settings-authentication.component.scss'],
})
-export class SettingsAuthenticationComponent implements OnInit {
+export class SettingsAuthenticationComponent implements OnInit, AfterViewInit {
+ @ViewChild('toggle') toggle: MatSlideToggle;
+
removeDialogTitle: string;
imgAtt: Attribute;
imageSrc = '';
removeDialogDescription: string;
mfaUrl = '';
displayImageBlock: boolean;
+ mfaAvailable = false;
+ mfaApiUrl = '';
+ loadingMfa = false;
+ loadingImg = false;
constructor(
private dialog: MatDialog,
private attributesManagerService: AttributesManagerService,
private store: StoreService,
- private translate: TranslateService
+ private translate: TranslateService,
+ private oauthService: OAuthService,
+ private authService: AuthService
) {
translate
.get('AUTHENTICATION.DELETE_IMG_DIALOG_TITLE')
@@ -34,7 +44,15 @@ export class SettingsAuthenticationComponent implements OnInit {
.subscribe((res) => (this.removeDialogDescription = res));
}
+ ngAfterViewInit(): void {
+ this.toggle.change.subscribe((change) => {
+ this.reAuthenticate(change.checked);
+ });
+ }
+
ngOnInit(): void {
+ this.loadingMfa = true;
+ this.loadingImg = true;
this.translate.onLangChange.subscribe(() => {
this.translate
.get('AUTHENTICATION.DELETE_IMG_DIALOG_TITLE')
@@ -45,9 +63,58 @@ export class SettingsAuthenticationComponent implements OnInit {
this.mfaUrl = this.store.get('mfa', 'url_' + this.translate.currentLang);
});
this.mfaUrl = this.store.get('mfa', 'url_' + this.translate.currentLang);
+ this.mfaApiUrl = this.store.get('mfa', 'api_url');
+ fetch(this.mfaApiUrl + 'mfaAvailable', {
+ method: 'GET',
+ headers: { Authorization: 'Bearer ' + this.oauthService.getIdToken() },
+ })
+ .then((response) => response.text())
+ .then((responseText) => {
+ this.mfaAvailable = responseText === 'true';
+ if (this.mfaAvailable) {
+ this.loadMfa();
+ }
+ })
+ .catch((e) => {
+ console.error(e);
+ this.loadingMfa = false;
+ });
+
this.loadImage();
}
+ private loadMfa(): void {
+ const mfaRoute = sessionStorage.getItem('mfa_route');
+ if (mfaRoute) {
+ const enforceMfa = sessionStorage.getItem('enforce_mfa');
+ this.enableMfa(enforceMfa === 'true')
+ .then((res) => {
+ if (res.ok && enforceMfa === 'true') {
+ this.toggle.toggle();
+ }
+ this.loadingMfa = false;
+ })
+ .catch((e) => {
+ console.error(e);
+ this.loadingMfa = false;
+ });
+ } else {
+ const enforceMfaAttributeName = this.store.get('mfa', 'enforce_mfa_attribute');
+ this.attributesManagerService
+ .getUserAttributeByName(this.store.getPerunPrincipal().userId, enforceMfaAttributeName)
+ .subscribe((attr) => {
+ if (attr.value) {
+ this.toggle.toggle();
+ }
+ this.loadingMfa = false;
+ });
+ }
+ if (sessionStorage.getItem('mfa_route')) {
+ sessionStorage.removeItem('enforce_mfa');
+ sessionStorage.removeItem('mfa_route');
+ }
+ }
+
onAddImg() {
const config = getDefaultDialogConfig();
config.width = '500px';
@@ -62,13 +129,29 @@ export class SettingsAuthenticationComponent implements OnInit {
});
}
- // private transformTextToImg(text: string) {
- // const canvas = document.createElement('canvas');
- // const context = canvas.getContext('2d');
- // context.font = "100px Calibri";
- // context.fillText(text, 1, 70);
- // return canvas.toDataURL('image/png');
- // }
+ reAuthenticate(enforceMfa: boolean): void {
+ sessionStorage.setItem('enforce_mfa', enforceMfa.toString());
+ sessionStorage.setItem('mfa_route', '/profile/settings/auth');
+ localStorage.removeItem('refresh_token');
+ this.oauthService.logOut(true);
+ sessionStorage.setItem('auth:redirect', location.pathname);
+ sessionStorage.setItem('auth:queryParams', location.search.substring(1));
+ this.authService.loadConfigData();
+ this.oauthService.loadDiscoveryDocumentAndLogin();
+ }
+
+ enableMfa(value: boolean): Promise {
+ const idToken = this.oauthService.getIdToken();
+ const path = `mfaEnforced`;
+ const url = `${this.mfaApiUrl}${path}`;
+ const body = `value=${value}`;
+
+ return fetch(url, {
+ method: 'PUT',
+ body: body,
+ headers: { Authorization: `Bearer ${idToken}` },
+ });
+ }
onDeleteImg() {
const config = getDefaultDialogConfig();
@@ -95,17 +178,28 @@ export class SettingsAuthenticationComponent implements OnInit {
this.displayImageBlock = this.store.get('mfa', 'enable_security_image');
this.attributesManagerService
.getUserAttributeByName(this.store.getPerunPrincipal().userId, imgAttributeName)
- .subscribe((attr) => {
- if (!attr) {
- this.attributesManagerService
- .getAttributeDefinitionByName(imgAttributeName)
- .subscribe((att) => {
- this.imgAtt = att as Attribute;
- });
- } else {
- this.imgAtt = attr;
- this.imageSrc = this.imgAtt.value as unknown as string;
+ .subscribe(
+ (attr) => {
+ if (!attr) {
+ this.attributesManagerService
+ .getAttributeDefinitionByName(imgAttributeName)
+ .subscribe((att) => {
+ this.imgAtt = att as Attribute;
+ });
+ } else {
+ this.imgAtt = attr;
+ this.imageSrc = this.imgAtt.value as unknown as string;
+ }
+ this.loadingImg = false;
+ },
+ (e) => {
+ console.error(e);
+ this.loadingImg = false;
}
- });
+ );
+ }
+
+ redirectToMfa(): void {
+ window.open(this.mfaUrl, '_blank');
}
}
diff --git a/apps/user-profile/src/assets/config/defaultConfig.json b/apps/user-profile/src/assets/config/defaultConfig.json
index ca208ecec..a9a2ac9c0 100644
--- a/apps/user-profile/src/assets/config/defaultConfig.json
+++ b/apps/user-profile/src/assets/config/defaultConfig.json
@@ -70,6 +70,7 @@
"api_url": "https://id.muni.cz/mfaapi/",
"enable_security_image": true,
"security_image_attribute": "urn:perun:user:attribute-def:def:securityImage:mu",
+ "enforce_mfa_attribute": "urn:perun:user:attribute-def:def:mfaEnforced:mu",
"url_en": "https://mfa.aai.muni.cz/",
"url_cs": "https://mfa.aai.muni.cz/"
},
diff --git a/apps/user-profile/src/assets/i18n/cs.json b/apps/user-profile/src/assets/i18n/cs.json
index ab6f4782a..868418a63 100644
--- a/apps/user-profile/src/assets/i18n/cs.json
+++ b/apps/user-profile/src/assets/i18n/cs.json
@@ -136,12 +136,14 @@
"AUTHENTICATION": {
"TITLE": "Bezpečnostní obrázek",
"MFA": "Vícefázové ověření",
+ "MFA_TOGGLE": "Zapnout vícefázové ověření pro všechny služby",
+ "MFA_DISABLED": "Potřebujete mít alespoň jeden aktivní MFA token.",
"NEW_IMG": "Nový obrázek",
"DELETE_IMG": "Vymazat obrázek",
"ANTI_PHISHING_INFO": "Tento bezpečnostní obrázek se vám ukáže před tím, než zadáte heslo, ujistíte se tak, že se nepřihlašujete na podvrženou stránku",
"DELETE_IMG_DIALOG_TITLE": "Vymazat proti-phishingový obrázek",
"DELETE_IMG_DIALOG_DESC": "Váš bezpečnostní obrázek bude odstraněn a nebude použit během autentizace.",
- "MFA_INFO": "Pro správu prostředků vícefázového ověření (MFA) navštivte "
+ "MFA_INFO": "Spravovat moje prostředky vícefázového ověření (MFA)"
},
"DIALOGS": {
"CHANGE_EMAIL": {
diff --git a/apps/user-profile/src/assets/i18n/en.json b/apps/user-profile/src/assets/i18n/en.json
index 7b9f1b733..6baffa08c 100644
--- a/apps/user-profile/src/assets/i18n/en.json
+++ b/apps/user-profile/src/assets/i18n/en.json
@@ -136,12 +136,14 @@
"AUTHENTICATION": {
"TITLE": "Security image",
"MFA": "Multi-factor authentication",
+ "MFA_TOGGLE": "Turn on multi-factor authentication for all services",
+ "MFA_DISABLED": "You need to have at least one active MFA token.",
"NEW_IMG": "New image",
"DELETE_IMG": "Delete image",
"ANTI_PHISHING_INFO": "You will be shown this security image before you enter your password so you will know that you are visiting the right site",
"DELETE_IMG_DIALOG_TITLE": "Delete anti-phishing image",
"DELETE_IMG_DIALOG_DESC": "Your security image will be deleted and will not be used during authentication process.",
- "MFA_INFO": "To manage MFA tokens go to "
+ "MFA_INFO": "Manage my MFA tokens"
},
"DIALOGS": {
"CHANGE_EMAIL": {
diff --git a/libs/perun/openapi/src/lib/api/attributesManager.service.ts b/libs/perun/openapi/src/lib/api/attributesManager.service.ts
index a66adabb4..fe6b7aca9 100644
--- a/libs/perun/openapi/src/lib/api/attributesManager.service.ts
+++ b/libs/perun/openapi/src/lib/api/attributesManager.service.ts
@@ -25,9 +25,11 @@ import { Observable } from 'rxjs';
import { Attribute } from '../model/attribute';
import { AttributeDefinition } from '../model/attributeDefinition';
+import { AttributePolicyCollection } from '../model/attributePolicyCollection';
import { AttributeRights } from '../model/attributeRights';
import { InlineResponse200 } from '../model/inlineResponse200';
import { InputAttributeDefinition } from '../model/inputAttributeDefinition';
+import { InputAttributePolicyCollections } from '../model/inputAttributePolicyCollections';
import { InputAttributeRights } from '../model/inputAttributeRights';
import { InputCreateAttributeDefinition } from '../model/inputCreateAttributeDefinition';
import { InputEntitylessAttribute } from '../model/inputEntitylessAttribute';
@@ -1122,6 +1124,85 @@ export class AttributesManagerService {
);
}
+ /**
+ * Gets attribute policy collections for an attribute definition with given id.
+ * @param attributeId id of AttributeDefinition
+ * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
+ * @param reportProgress flag to report request and response progress.
+ */
+ public getAttributePolicyCollections(
+ attributeId: number,
+ observe?: 'body',
+ reportProgress?: boolean
+ ): Observable>;
+ public getAttributePolicyCollections(
+ attributeId: number,
+ observe?: 'response',
+ reportProgress?: boolean
+ ): Observable>>;
+ public getAttributePolicyCollections(
+ attributeId: number,
+ observe?: 'events',
+ reportProgress?: boolean
+ ): Observable>>;
+ public getAttributePolicyCollections(
+ attributeId: number,
+ observe: any = 'body',
+ reportProgress: boolean = false
+ ): Observable {
+ if (attributeId === null || attributeId === undefined) {
+ throw new Error(
+ 'Required parameter attributeId was null or undefined when calling getAttributePolicyCollections.'
+ );
+ }
+
+ let queryParameters = new HttpParams({ encoder: this.encoder });
+ if (attributeId !== undefined && attributeId !== null) {
+ queryParameters = queryParameters.set('attributeId', attributeId);
+ }
+
+ let headers = this.defaultHeaders;
+
+ // authentication (ApiKeyAuth) required
+ if (this.configuration.apiKeys && this.configuration.apiKeys['Authorization']) {
+ headers = headers.set('Authorization', this.configuration.apiKeys['Authorization']);
+ }
+
+ // authentication (BasicAuth) required
+ if (this.configuration.username || this.configuration.password) {
+ headers = headers.set(
+ 'Authorization',
+ 'Basic ' + btoa(this.configuration.username + ':' + this.configuration.password)
+ );
+ }
+ // authentication (BearerAuth) required
+ if (this.configuration.accessToken) {
+ const accessToken =
+ typeof this.configuration.accessToken === 'function'
+ ? this.configuration.accessToken()
+ : this.configuration.accessToken;
+ headers = headers.set('Authorization', 'Bearer ' + accessToken);
+ }
+ // to determine the Accept header
+ const httpHeaderAccepts: string[] = ['application/json'];
+ const httpHeaderAcceptSelected: string | undefined =
+ this.configuration.selectHeaderAccept(httpHeaderAccepts);
+ if (httpHeaderAcceptSelected !== undefined) {
+ headers = headers.set('Accept', httpHeaderAcceptSelected);
+ }
+
+ return this.httpClient.get>(
+ `${this.configuration.basePath}/json/attributesManager/getAttributePolicyCollections`,
+ {
+ params: queryParameters,
+ withCredentials: this.configuration.withCredentials,
+ headers: headers,
+ observe: observe,
+ reportProgress: reportProgress,
+ }
+ );
+ }
+
/**
* Gets AttributeRights for specified Attribute. Rights specify which Role can do particular actions (read / write) with Attribute. Method always return rights for following roles: VOADMIN, GROUPADMIN, FACILITYADMIN, SELF.
* @param attributeId id of AttributeDefinition
@@ -12011,6 +12092,88 @@ export class AttributesManagerService {
);
}
+ /**
+ * Deletes old attribute policy collections and sets attribute policy collections for an attribute definition provided in given policy collections.
+ * @param inputAttributePolicyCollections
+ * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
+ * @param reportProgress flag to report request and response progress.
+ */
+ public setAttributePolicyCollections(
+ inputAttributePolicyCollections: InputAttributePolicyCollections,
+ observe?: 'body',
+ reportProgress?: boolean
+ ): Observable;
+ public setAttributePolicyCollections(
+ inputAttributePolicyCollections: InputAttributePolicyCollections,
+ observe?: 'response',
+ reportProgress?: boolean
+ ): Observable>;
+ public setAttributePolicyCollections(
+ inputAttributePolicyCollections: InputAttributePolicyCollections,
+ observe?: 'events',
+ reportProgress?: boolean
+ ): Observable>;
+ public setAttributePolicyCollections(
+ inputAttributePolicyCollections: InputAttributePolicyCollections,
+ observe: any = 'body',
+ reportProgress: boolean = false
+ ): Observable {
+ if (inputAttributePolicyCollections === null || inputAttributePolicyCollections === undefined) {
+ throw new Error(
+ 'Required parameter inputAttributePolicyCollections was null or undefined when calling setAttributePolicyCollections.'
+ );
+ }
+
+ let headers = this.defaultHeaders;
+
+ // authentication (ApiKeyAuth) required
+ if (this.configuration.apiKeys && this.configuration.apiKeys['Authorization']) {
+ headers = headers.set('Authorization', this.configuration.apiKeys['Authorization']);
+ }
+
+ // authentication (BasicAuth) required
+ if (this.configuration.username || this.configuration.password) {
+ headers = headers.set(
+ 'Authorization',
+ 'Basic ' + btoa(this.configuration.username + ':' + this.configuration.password)
+ );
+ }
+ // authentication (BearerAuth) required
+ if (this.configuration.accessToken) {
+ const accessToken =
+ typeof this.configuration.accessToken === 'function'
+ ? this.configuration.accessToken()
+ : this.configuration.accessToken;
+ headers = headers.set('Authorization', 'Bearer ' + accessToken);
+ }
+ // to determine the Accept header
+ const httpHeaderAccepts: string[] = ['application/json'];
+ const httpHeaderAcceptSelected: string | undefined =
+ this.configuration.selectHeaderAccept(httpHeaderAccepts);
+ if (httpHeaderAcceptSelected !== undefined) {
+ headers = headers.set('Accept', httpHeaderAcceptSelected);
+ }
+
+ // to determine the Content-Type header
+ const consumes: string[] = ['application/json'];
+ const httpContentTypeSelected: string | undefined =
+ this.configuration.selectHeaderContentType(consumes);
+ if (httpContentTypeSelected !== undefined) {
+ headers = headers.set('Content-Type', httpContentTypeSelected);
+ }
+
+ return this.httpClient.post(
+ `${this.configuration.basePath}/json/attributesManager/setAttributePolicyCollections`,
+ inputAttributePolicyCollections,
+ {
+ withCredentials: this.configuration.withCredentials,
+ headers: headers,
+ observe: observe,
+ reportProgress: reportProgress,
+ }
+ );
+ }
+
/**
* Sets all AttributeRights in the list given as a parameter. Allowed Roles to set rights for are: VOADMIN, GROUPADMIN, FACILITYADMIN, SELF.
* @param inputAttributeRights
diff --git a/libs/perun/openapi/src/lib/api/authzResolver.service.ts b/libs/perun/openapi/src/lib/api/authzResolver.service.ts
index 8d49954d8..359a4b5a4 100644
--- a/libs/perun/openapi/src/lib/api/authzResolver.service.ts
+++ b/libs/perun/openapi/src/lib/api/authzResolver.service.ts
@@ -296,8 +296,8 @@ export class AuthzResolverService {
}
/**
- * Gets all rich admins
- * Returns all managers for complementaryObject and role with specified attributes.
+ * Gets all valid rich admins
+ * Get all valid richUser administrators (for group-based rights, status must be VALID for both Vo and group) for complementary object and role with specified attributes.
* @param role
* @param complementaryObjectId Property id of complementaryObject to get managers for
* @param complementaryObjectName Property beanName of complementaryObject, meaning object type (Vo | Group | Facility | ... )
diff --git a/libs/perun/openapi/src/lib/api/facilitiesManager.service.ts b/libs/perun/openapi/src/lib/api/facilitiesManager.service.ts
index 145137563..42de7a3ed 100644
--- a/libs/perun/openapi/src/lib/api/facilitiesManager.service.ts
+++ b/libs/perun/openapi/src/lib/api/facilitiesManager.service.ts
@@ -5319,7 +5319,7 @@ export class FacilitiesManagerService {
}
/**
- * Returns list of Facilities, where the user is an Administrator.
+ * Returns list of Facilities, where the user is a direct Administrator or a VALID member of an administrator group.
* @param user id of User
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
@@ -5477,7 +5477,7 @@ export class FacilitiesManagerService {
}
/**
- * Get list of all facility administrators for supported role and given facility. If onlyDirectAdmins is true, return only direct admins of the group for supported role. Supported roles: FacilityAdmin
+ * Get list of all facility administrators for supported role and given facility. If onlyDirectAdmins is true, return only direct admins of the group for supported role. Includes users who are VALID members of administrator groups. Supported roles: FacilityAdmin
* @param facility id of Facility
* @param onlyDirectAdmins if true, get only direct facility administrators (if false, get both direct and indirect)
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
@@ -5569,7 +5569,7 @@ export class FacilitiesManagerService {
}
/**
- * Get list of all facility administrators for supported role and given facility. If onlyDirectAdmins is true, return only direct admins of the group for supported role. Supported roles: FacilityAdmin
+ * Get list of all facility administrators for supported role and given facility. If onlyDirectAdmins is true, return only direct admins of the group for supported role. Includes users who are VALID members of administrator groups. Supported roles: FacilityAdmin
* @param facility name of Facility
* @param onlyDirectAdmins if true, get only direct facility administrators (if false, get both direct and indirect)
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
diff --git a/libs/perun/openapi/src/lib/api/registrarManager.service.ts b/libs/perun/openapi/src/lib/api/registrarManager.service.ts
index ec34b3ea7..856a60756 100644
--- a/libs/perun/openapi/src/lib/api/registrarManager.service.ts
+++ b/libs/perun/openapi/src/lib/api/registrarManager.service.ts
@@ -42,7 +42,7 @@ import { InputUpdateApplicationMail } from '../model/inputUpdateApplicationMail'
import { InputUpdateForm } from '../model/inputUpdateForm';
import { InputUpdateFormItemsForGroup } from '../model/inputUpdateFormItemsForGroup';
import { InputUpdateFormItemsForVo } from '../model/inputUpdateFormItemsForVo';
-import { PaginatedApplications } from '../model/paginatedApplications';
+import { PaginatedRichApplications } from '../model/paginatedRichApplications';
import { PerunException } from '../model/perunException';
import { UserExtSource } from '../model/userExtSource';
@@ -2327,17 +2327,17 @@ export class RegistrarManagerService {
inputGetPaginatedApplications: InputGetPaginatedApplications,
observe?: 'body',
reportProgress?: boolean
- ): Observable;
+ ): Observable;
public getApplicationsPage(
inputGetPaginatedApplications: InputGetPaginatedApplications,
observe?: 'response',
reportProgress?: boolean
- ): Observable>;
+ ): Observable>;
public getApplicationsPage(
inputGetPaginatedApplications: InputGetPaginatedApplications,
observe?: 'events',
reportProgress?: boolean
- ): Observable>;
+ ): Observable>;
public getApplicationsPage(
inputGetPaginatedApplications: InputGetPaginatedApplications,
observe: any = 'body',
@@ -2387,7 +2387,7 @@ export class RegistrarManagerService {
headers = headers.set('Content-Type', httpContentTypeSelected);
}
- return this.httpClient.post(
+ return this.httpClient.post(
`${this.configuration.basePath}/json/registrarManager/getApplicationsPage`,
inputGetPaginatedApplications,
{
diff --git a/libs/perun/openapi/src/lib/api/resourcesManager.service.ts b/libs/perun/openapi/src/lib/api/resourcesManager.service.ts
index f68858cc5..b2747587f 100644
--- a/libs/perun/openapi/src/lib/api/resourcesManager.service.ts
+++ b/libs/perun/openapi/src/lib/api/resourcesManager.service.ts
@@ -2243,7 +2243,7 @@ export class ResourcesManagerService {
/**
* Get list of all resource administrators for supported role and given resource.
- * If onlyDirectAdmins is == true, return only direct admins of the group for supported role. Supported roles are ResourceAdmin, VOAdmin.
+ * If onlyDirectAdmins is == true, return only direct admins of the group for supported role. Otherwise include users who are VALID members of administrator groups. Supported roles are ResourceAdmin, VOAdmin.
* @param resource id of Resource
* @param onlyDirectAdmins boolean if true, get only direct resource administrators (if false, get both direct and indirect)
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
@@ -3137,7 +3137,7 @@ export class ResourcesManagerService {
}
/**
- * List all resources associated with a group.
+ * List all resources to which the group is assigned.
* @param group id of Group
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
@@ -5310,7 +5310,7 @@ export class ResourcesManagerService {
}
/**
- * Returns list of Resources for specified VO and Facility, where the user is an Administrator.
+ * Returns list of Resources for specified VO and Facility, where the user is a direct Administrator or a VALID member of an administrator group.
* @param facility id of Facility
* @param vo id of Vo
* @param user id of User
@@ -5415,7 +5415,7 @@ export class ResourcesManagerService {
}
/**
- * Get list of all richUser administrators for the resource and supported role with specific attributes. Supported roles: ResourceAdmin, VOAdmin If \"onlyDirectAdmins\" is true, return only direct admins of the resource for supported role with specific attributes. If \"allUserAttributes\" is true, do not specify attributes through list and return them all in objects richUser. Ignoring list of specific attributes.
+ * Get list of all richUser administrators for the resource and supported role with specific attributes. If some group is administrator of the given group, all VALID members are included in the list. Supported roles: ResourceAdmin, VOAdmin If \"onlyDirectAdmins\" is true, return only direct admins of the resource for supported role with specific attributes. If \"allUserAttributes\" is true, do not specify attributes through list and return them all in objects richUser. Ignoring list of specific attributes.
* @param resource id of Resource
* @param specificAttributes list of specified attributes which are needed in object richUser
* @param allUserAttributes if == true, get all possible user attributes and ignore list of specificAttributes (if false, get only specific attributes)
diff --git a/libs/perun/openapi/src/lib/api/usersManager.service.ts b/libs/perun/openapi/src/lib/api/usersManager.service.ts
index 4294a1b78..96009ff26 100644
--- a/libs/perun/openapi/src/lib/api/usersManager.service.ts
+++ b/libs/perun/openapi/src/lib/api/usersManager.service.ts
@@ -2096,7 +2096,7 @@ export class UsersManagerService {
}
/**
- * Returns list of Groups in selected Vo, where the User is a direct Administrator or he is a member of any group which is Administrator of some of these Groups.
+ * Returns list of Groups in selected Vo, where the User is a direct Administrator or he is a VALID member of any group which is Administrator of some of these Groups.
* @param user id of User
* @param vo id of Vo
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
@@ -2188,7 +2188,7 @@ export class UsersManagerService {
}
/**
- * Returns list of Groups in Perun, where the User is a direct Administrator or he is a member of any group which is Administrator of some of these Groups.
+ * Returns list of Groups in Perun, where the User is a direct Administrator or he is a VALID member of any group which is Administrator of some of these Groups.
* @param user id of User
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
@@ -3909,7 +3909,7 @@ export class UsersManagerService {
}
/**
- * Returns list of VOs, where the user is an Administrator.
+ * Returns list of VOs, where the user is an Administrator. If a group, of which the user is a valid member, is an administrator of a VO, include that VO as well.
* @param user id of User
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
diff --git a/libs/perun/openapi/src/lib/api/vosManager.service.ts b/libs/perun/openapi/src/lib/api/vosManager.service.ts
index 81a2e0c58..b0d825f58 100644
--- a/libs/perun/openapi/src/lib/api/vosManager.service.ts
+++ b/libs/perun/openapi/src/lib/api/vosManager.service.ts
@@ -1200,7 +1200,7 @@ export class VosManagerService {
}
/**
- * Get list of all richUser administrators for the vo and supported role with specific attributes. Supported roles: VOOBSERVER, TOPGROUPCREATOR, VOADMIN If \"onlyDirectAdmins\" is == true, return only direct admins of the vo for supported role with specific attributes. If \"allUserAttributes\" is == true, do not specify attributes through list and return them all in objects richUser. Ignoring list of specific attributes.
+ * Get list of all richUser administrators for the vo and supported role with specific attributes. If some group is administrator of the given group, all VALID members are included in the list. Supported roles: VOOBSERVER, TOPGROUPCREATOR, VOADMIN If \"onlyDirectAdmins\" is == true, return only direct admins of the vo for supported role with specific attributes. If \"allUserAttributes\" is == true, do not specify attributes through list and return them all in objects richUser. Ignoring list of specific attributes.
* @param vo id of Vo
* @param role role name
* @param specificAttributes list of specified attributes which are needed in object richUser
@@ -1423,7 +1423,7 @@ export class VosManagerService {
}
/**
- * Get list of all vo administrators for supported role and specific vo. If onlyDirectAdmins is true, return only direct admins of the vo for supported role. Supported roles: VOOBSERVER, TOPGROUPCREATOR, VOADMIN
+ * Get list of all vo administrators for supported role and specific vo. If onlyDirectAdmins is true, return only direct admins of the vo for supported role. Otherwise return direct admins and users who are VALID members of administrator groups Supported roles: VOOBSERVER, TOPGROUPCREATOR, VOADMIN
* @param vo id of Vo
* @param role supported role name
* @param onlyDirectAdmins get only direct administrators (if false, get both direct and indirect)
@@ -1835,25 +1835,31 @@ export class VosManagerService {
* @param reportProgress flag to report request and response progress.
*/
public getVoByShortName(
- shortName?: string,
+ shortName: string,
observe?: 'body',
reportProgress?: boolean
): Observable;
public getVoByShortName(
- shortName?: string,
+ shortName: string,
observe?: 'response',
reportProgress?: boolean
): Observable>;
public getVoByShortName(
- shortName?: string,
+ shortName: string,
observe?: 'events',
reportProgress?: boolean
): Observable>;
public getVoByShortName(
- shortName?: string,
+ shortName: string,
observe: any = 'body',
reportProgress: boolean = false
): Observable {
+ if (shortName === null || shortName === undefined) {
+ throw new Error(
+ 'Required parameter shortName was null or undefined when calling getVoByShortName.'
+ );
+ }
+
let queryParameters = new HttpParams({ encoder: this.encoder });
if (shortName !== undefined && shortName !== null) {
queryParameters = queryParameters.set('shortName', shortName);
diff --git a/libs/perun/openapi/src/lib/model/applicationsPageQuery.ts b/libs/perun/openapi/src/lib/model/applicationsPageQuery.ts
index eb75e693f..23ddf2a10 100644
--- a/libs/perun/openapi/src/lib/model/applicationsPageQuery.ts
+++ b/libs/perun/openapi/src/lib/model/applicationsPageQuery.ts
@@ -20,6 +20,7 @@ export interface ApplicationsPageQuery {
sortColumn: ApplicationsOrderColumn;
searchString?: string;
includeGroupApplications?: boolean;
+ getDetails?: boolean;
states?: Array;
dateFrom?: string;
dateTo?: string;
diff --git a/libs/perun/openapi/src/lib/model/attributeDefinition.ts b/libs/perun/openapi/src/lib/model/attributeDefinition.ts
index 2683a9939..e849b9617 100644
--- a/libs/perun/openapi/src/lib/model/attributeDefinition.ts
+++ b/libs/perun/openapi/src/lib/model/attributeDefinition.ts
@@ -14,7 +14,7 @@ import { Auditable } from './auditable';
export interface AttributeDefinition extends Auditable {
friendlyName?: string;
namespace?: string;
- description?: string;
+ description?: string | null;
type?: string;
displayName?: string;
writable?: boolean;
diff --git a/libs/perun/openapi/src/lib/model/group.ts b/libs/perun/openapi/src/lib/model/group.ts
index d7c6a8c2e..40d7c8618 100644
--- a/libs/perun/openapi/src/lib/model/group.ts
+++ b/libs/perun/openapi/src/lib/model/group.ts
@@ -14,8 +14,8 @@ import { Auditable } from './auditable';
export interface Group extends Auditable {
name?: string;
shortName?: string;
- description?: string;
+ description?: string | null;
voId?: number;
- parentGroupId?: number;
+ parentGroupId?: number | null;
uuid?: string;
}
diff --git a/libs/perun/openapi/src/lib/model/models.ts b/libs/perun/openapi/src/lib/model/models.ts
index cc66d6ae5..b8c4bb2ac 100644
--- a/libs/perun/openapi/src/lib/model/models.ts
+++ b/libs/perun/openapi/src/lib/model/models.ts
@@ -166,8 +166,8 @@ export * from './membersPageQuery';
export * from './namespaceRules';
export * from './newApps';
export * from './owner';
-export * from './paginatedApplications';
export * from './paginatedAuditMessages';
+export * from './paginatedRichApplications';
export * from './paginatedRichGroups';
export * from './paginatedRichMembers';
export * from './paginatedRichUsers';
@@ -183,6 +183,7 @@ export * from './rTMessage';
export * from './resource';
export * from './resourceState';
export * from './resourceTag';
+export * from './richApplication';
export * from './richDestination';
export * from './richFacility';
export * from './richGroup';
diff --git a/libs/perun/openapi/src/lib/model/paginatedRichApplications.ts b/libs/perun/openapi/src/lib/model/paginatedRichApplications.ts
new file mode 100644
index 000000000..a6a1f7f13
--- /dev/null
+++ b/libs/perun/openapi/src/lib/model/paginatedRichApplications.ts
@@ -0,0 +1,19 @@
+/**
+ * Perun RPC API
+ * Perun Remote Procedure Calls Application Programming Interface
+ *
+ * The version of the OpenAPI document: 0.0.0
+ * Contact: perun@cesnet.cz
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+import { RichApplication } from './richApplication';
+
+export interface PaginatedRichApplications {
+ offset: number;
+ pageSize: number;
+ totalCount: number;
+ data: Array;
+}
diff --git a/libs/perun/openapi/src/lib/model/richApplication.ts b/libs/perun/openapi/src/lib/model/richApplication.ts
new file mode 100644
index 000000000..ae56dcb15
--- /dev/null
+++ b/libs/perun/openapi/src/lib/model/richApplication.ts
@@ -0,0 +1,22 @@
+/**
+ * Perun RPC API
+ * Perun Remote Procedure Calls Application Programming Interface
+ *
+ * The version of the OpenAPI document: 0.0.0
+ * Contact: perun@cesnet.cz
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+import { Group } from './group';
+import { User } from './user';
+import { Vo } from './vo';
+import { ApplicationFormItemData } from './applicationFormItemData';
+import { AppState } from './appState';
+import { AppType } from './appType';
+import { Application } from './application';
+
+export interface RichApplication {
+ formData: Array;
+}
diff --git a/libs/perun/services/src/lib/auth.service.ts b/libs/perun/services/src/lib/auth.service.ts
index 220f1a9bb..73d5bf337 100644
--- a/libs/perun/services/src/lib/auth.service.ts
+++ b/libs/perun/services/src/lib/auth.service.ts
@@ -44,7 +44,11 @@ export class AuthService {
) {
customQueryParams['prompt'] = 'consent';
}
-
+ if (sessionStorage.getItem('mfa_route')) {
+ customQueryParams['acr_values'] = 'https://refeds.org/profile/mfa';
+ customQueryParams['prompt'] = 'login';
+ customQueryParams['max_age'] = '0';
+ }
return {
requestAccessToken: true,
issuer: this.store.get('oidc_client', 'oauth_authority'),
diff --git a/libs/perun/services/src/lib/dynamic-paginating.service.ts b/libs/perun/services/src/lib/dynamic-paginating.service.ts
index 99824d5cd..233ce67ad 100644
--- a/libs/perun/services/src/lib/dynamic-paginating.service.ts
+++ b/libs/perun/services/src/lib/dynamic-paginating.service.ts
@@ -6,7 +6,7 @@ import {
MemberGroupStatus,
MembersManagerService,
MembersOrderColumn,
- PaginatedApplications,
+ PaginatedRichApplications,
PaginatedAuditMessages,
PaginatedRichMembers,
PaginatedRichUsers,
@@ -115,8 +115,9 @@ export class DynamicPaginatingService {
dateTo: string,
userId: number,
voId: number,
- groupId: number
- ): Observable {
+ groupId: number,
+ getDetails: boolean
+ ): Observable {
return this.registrarService.getApplicationsPage({
vo: voId,
query: {
@@ -124,8 +125,9 @@ export class DynamicPaginatingService {
offset: pageIndex * pageSize,
order: sortOrder,
sortColumn: sortColumn,
- includeGroupApplications: includeGroupApps,
searchString: searchString,
+ includeGroupApplications: includeGroupApps,
+ getDetails: getDetails,
states: states,
dateFrom: dateFrom,
dateTo: dateTo,
diff --git a/libs/perun/services/src/lib/dynamicDataSource.ts b/libs/perun/services/src/lib/dynamicDataSource.ts
index 696c5863d..b99532a8b 100644
--- a/libs/perun/services/src/lib/dynamicDataSource.ts
+++ b/libs/perun/services/src/lib/dynamicDataSource.ts
@@ -1,6 +1,4 @@
import { DataSource } from '@angular/cdk/collections';
-import { Observable, BehaviorSubject, of } from 'rxjs';
-import { catchError, finalize } from 'rxjs/operators';
import {
Application,
ApplicationsOrderColumn,
@@ -8,7 +6,7 @@ import {
AuditMessage,
MemberGroupStatus,
MembersOrderColumn,
- PaginatedApplications,
+ PaginatedRichApplications,
PaginatedAuditMessages,
PaginatedRichMembers,
PaginatedRichUsers,
@@ -18,6 +16,8 @@ import {
UsersOrderColumn,
VoMemberStatuses,
} from '@perun-web-apps/perun/openapi';
+import { BehaviorSubject, Observable, of } from 'rxjs';
+import { catchError, finalize } from 'rxjs/operators';
import { DynamicPaginatingService } from './dynamic-paginating.service';
import { GuiAuthResolver } from './gui-auth-resolver.service';
@@ -168,7 +168,8 @@ export class DynamicDataSource implements DataSource {
dateTo: string,
userId: number,
groupId: number,
- voId: number
+ voId: number,
+ details?: boolean
) {
this.loadingSubject.next(true);
this.latestQueryTime = Date.now();
@@ -187,7 +188,8 @@ export class DynamicDataSource implements DataSource {
dateTo,
userId,
voId,
- groupId
+ groupId,
+ details ?? false
)
.pipe(
catchError(() => of([])),
@@ -195,21 +197,22 @@ export class DynamicDataSource implements DataSource {
)
.subscribe((paginatedApplications) => {
if (this.latestQueryTime <= thisQueryTime) {
- const data: Application[] = (paginatedApplications).data;
+ const data = (paginatedApplications).data;
if (data !== null && data.length !== 0) {
- if (data[0].group) {
+ const d = data;
+ if (d[0].group) {
this.routeAuth = this.authzService.isAuthorized(
'getApplicationsForGroup_Group_List_policy',
- [data[0].group]
+ [d[0].group]
);
} else {
this.routeAuth = this.authzService.isAuthorized(
'getApplicationsForVo_Vo_List_Boolean_policy',
- [data[0].vo]
+ [d[0].vo]
);
}
}
- this.allObjectCount = (paginatedApplications).totalCount;
+ this.allObjectCount = (paginatedApplications).totalCount;
// @ts-ignore
this.dataSubject.next(data);
}
diff --git a/package-lock.json b/package-lock.json
index 2cb4bdf5c..53a57fd94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15066,9 +15066,9 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
- "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/lodash.assign": {
"version": "4.2.0",
@@ -15654,9 +15654,9 @@
}
},
"node_modules/minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"node_modules/minimist-options": {
"version": "4.1.0",
@@ -35184,9 +35184,9 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash-es": {
- "version": "4.17.15",
- "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
- "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"lodash.assign": {
"version": "4.2.0",
@@ -35622,9 +35622,9 @@
}
},
"minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"minimist-options": {
"version": "4.1.0",