SUPPORT-9346: fix access to application pages

This commit is contained in:
gulnaz 2025-08-29 11:52:11 +03:00
parent 44681d41d3
commit 3a4a733c4b
8 changed files with 183 additions and 13 deletions

View file

@ -0,0 +1,32 @@
package ru.micord.ervu.account_applications.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import ru.micord.ervu.account_applications.security.context.SecurityContext;
import ru.micord.ervu.account_applications.service.RecruitmentService;
/**
* @author gulnaz
*/
@Controller
public class RecruitmentController {
private final SecurityContext securityContext;
private final RecruitmentService recruitmentService;
public RecruitmentController(SecurityContext securityContext, RecruitmentService recruitmentService) {
this.securityContext = securityContext;
this.recruitmentService = recruitmentService;
}
@GetMapping(value = "/allowed")
public ResponseEntity<Boolean> checkAccess(HttpServletRequest request) {
Long appNumber = Long.valueOf(request.getHeader("app-number"));
boolean checkParents = Boolean.parseBoolean(request.getHeader("check-parents"));
String domainId = securityContext.getDomainId();
return ResponseEntity.ok(recruitmentService.exists(appNumber, domainId, checkParents));
}
}

View file

@ -5,12 +5,16 @@ import java.util.Optional;
import java.util.UUID;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.Select;
import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.impl.DSL;
import org.springframework.stereotype.Repository;
import ru.micord.ervu.account_applications.db_beans.public_.Tables;
import ru.micord.ervu.account_applications.db_beans.public_.tables.Recruitment;
import ru.micord.ervu.account_applications.db_beans.public_.tables.UserApplicationList;
import ru.micord.ervu.account_applications.db_beans.public_.tables.records.RecruitmentRecord;
/**
@ -78,6 +82,43 @@ public class RecruitmentDao extends AbstractDataDao<RecruitmentRecord> {
setFieldByField(Recruitment.RECRUITMENT.ACTIVE, active, Recruitment.RECRUITMENT.IDM_ID, id);
}
public boolean exists(Long appNumber, String domainId, boolean checkParents) {
Recruitment orgTable = Recruitment.RECRUITMENT;
UserApplicationList appTable = UserApplicationList.USER_APPLICATION_LIST;
String parentOrg = "parent_org";
Name parentOrgName = DSL.name(parentOrg);
Table<?> parentOrgTable = DSL.table(parentOrgName);
Field<String> parentIdmId = DSL.field(DSL.name(parentOrg, orgTable.IDM_ID.getName()),
String.class
);
Field<String> parentParentId = DSL.field(DSL.name(parentOrg, orgTable.PARENT_ID.getName()),
String.class
);
Select<?> select = checkParents
? dsl.withRecursive(parentOrgName)
.as(dsl.select(orgTable.IDM_ID, orgTable.PARENT_ID)
.from(orgTable)
.where(orgTable.IDM_ID.eq(
dsl.select(orgTable.IDM_ID)
.from(orgTable)
.join(appTable).on(appTable.RECRUITMENT_ID.eq(orgTable.ID))
.where(appTable.NUMBER_APP.eq(appNumber))))
.unionAll(dsl.select(orgTable.IDM_ID, orgTable.PARENT_ID)
.from(orgTable)
.join(parentOrgTable).on(orgTable.IDM_ID.eq(parentParentId))))
.select(parentIdmId)
.from(parentOrgTable)
.where(parentIdmId.eq(domainId))
: dsl.select(orgTable.IDM_ID)
.from(orgTable)
.join(appTable)
.on(appTable.RECRUITMENT_ID.eq(orgTable.ID))
.where(appTable.NUMBER_APP.eq(appNumber)
.and(orgTable.IDM_ID.eq(domainId)));
return dsl.fetchExists(select);
}
@Override
protected Table<RecruitmentRecord> getTable() {
return Tables.RECRUITMENT;

View file

@ -16,6 +16,8 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
import ru.micord.ervu.account_applications.security.filter.JwtAuthenticationFilter;
import ru.micord.ervu.account_applications.security.provider.ErvuJwtAuthenticationProvider;
import static ru.micord.ervu.account_applications.security.config.SecurityConstant.CREATE_APPLICATION_AUTHORITY;
import static ru.micord.ervu.account_applications.security.config.SecurityConstant.CREATE_APPLICATION_PERMISSIONS;
@Configuration
@EnableWebSecurity
@ -34,6 +36,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
.authorizeHttpRequests(auth -> {
auth.antMatchers("/version").permitAll();
auth.antMatchers("/session").authenticated();
auth.antMatchers(CREATE_APPLICATION_PERMISSIONS).hasAuthority(CREATE_APPLICATION_AUTHORITY);
if (allowedRoles != null && allowedRoles.length > 0) {
auth.anyRequest().hasAnyAuthority(allowedRoles);

View file

@ -0,0 +1,16 @@
package ru.micord.ervu.account_applications.security.config;
/**
* @author gulnaz
*/
public class SecurityConstant {
public static final String CREATE_APPLICATION_AUTHORITY = "responsible_for_information_security";
public static final String[] CREATE_APPLICATION_PERMISSIONS = {
"/rpc/add_user_application/**",
"/rpc/edit_user_application/**",
"/rpc/block_user_application/**",
"/rpc/unblock_user_application/**",
"/rpc/reset_password/**"
};
}

View file

@ -0,0 +1,21 @@
package ru.micord.ervu.account_applications.service;
import org.springframework.stereotype.Service;
import ru.micord.ervu.account_applications.dao.RecruitmentDao;
/**
* @author gulnaz
*/
@Service
public class RecruitmentService {
private final RecruitmentDao recruitmentDao;
public RecruitmentService(RecruitmentDao recruitmentDao) {
this.recruitmentDao = recruitmentDao;
}
public boolean exists(Long appNumber, String domainId, boolean checkParents) {
return recruitmentDao.exists(appNumber, domainId, checkParents);
}
}

View file

@ -2,7 +2,7 @@ import {NgModule} from "@angular/core";
import {RouterModule, Routes} from "@angular/router";
import {ConfirmExitGuard} from "@webbpm/base-package";
import {RolesGuard} from "./guard/RolesGuard";
import {ErvuRole} from "./enum/ErvuRole";
const appRoutes: Routes = [
{
@ -13,37 +13,58 @@ const appRoutes: Routes = [
{
path: 'add_user_application',
loadChildren: 'generated-sources/page-add_user_application.module#Pageadd_user_applicationModule',
canActivate: [ConfirmExitGuard, RolesGuard]
canActivate: [ConfirmExitGuard, RolesGuard],
data: {
roles: [ErvuRole.CREATOR]
}
},
{
path: 'edit_user_application',
loadChildren: 'generated-sources/page-edit_user_application.module#Pageedit_user_applicationModule',
canActivate: [ConfirmExitGuard, RolesGuard]
canActivate: [ConfirmExitGuard, RolesGuard],
data: {
roles: [ErvuRole.CREATOR]
}
},
{
path: 'block_user_application',
loadChildren: 'generated-sources/page-block_user_application.module#Pageblock_user_applicationModule',
canActivate: [ConfirmExitGuard, RolesGuard]
canActivate: [ConfirmExitGuard, RolesGuard],
data: {
roles: [ErvuRole.CREATOR]
}
},
{
path: 'reset_password',
loadChildren: 'generated-sources/page-reset_password.module#Pagereset_passwordModule',
canActivate: [ConfirmExitGuard, RolesGuard]
canActivate: [ConfirmExitGuard, RolesGuard],
data: {
roles: [ErvuRole.CREATOR]
}
},
{
path: 'process_application/:id',
loadChildren: 'generated-sources/page-process_application.module#Pageprocess_applicationModule',
canActivate: [ConfirmExitGuard, RolesGuard]
canActivate: [ConfirmExitGuard, RolesGuard],
data: {
checkOrg: true
}
},
{
path: 'process_application_edit_user/:id',
loadChildren: 'generated-sources/page-process_application_edit_user.module#Pageprocess_application_edit_userModule',
canActivate: [ConfirmExitGuard, RolesGuard]
canActivate: [ConfirmExitGuard, RolesGuard],
data: {
checkOrg: true
}
},
{
path: 'unblock_user_application',
loadChildren: 'generated-sources/page-unblock_user_application.module#Pageunblock_user_applicationModule',
canActivate: [ConfirmExitGuard, RolesGuard]
canActivate: [ConfirmExitGuard, RolesGuard],
data: {
roles: [ErvuRole.CREATOR]
}
}
];

View file

@ -0,0 +1,5 @@
export enum ErvuRole {
CREATOR = 'responsible_for_information_security',
REVIEWER = 'responsible_for_internal_control',
APPROVER = 'security_administrator'
}

View file

@ -8,15 +8,17 @@ import {
import {Injectable} from "@angular/core";
import {AuthorizationService} from "../service/authorization.service";
import {TokenProvider} from "../provider/token.provider";
import {HttpClient} from "@angular/common/http";
import {ErvuRole} from "../enum/ErvuRole";
@Injectable({providedIn: 'root'})
export class RolesGuard implements CanActivate{
protected readonly allowedRoles: string[] = [];
private allowedRoles: string[];
constructor(protected authService: AuthorizationService,
protected tokenProvider: TokenProvider,
protected router: Router) {
protected router: Router, private httpClient: HttpClient) {
}
async canActivate(
@ -25,14 +27,21 @@ export class RolesGuard implements CanActivate{
if (!await this.tokenProvider.getToken()) {
return this.getUrlOnFailure()
}
this.allowedRoles = route.data && route.data.roles ? route.data.roles : [];
let checkOrg = route.data && route.data.checkOrg;
if (!this.authService.isAuthorized()) {
return this.authService.getCurrentSession()
.then(() => this.checkRoles() ? true : this.getUrlOnFailure())
.then(() => {
if (checkOrg) {
return this.checkOrgByAppId(route.params.id);
}
return this.checkRoles() ? true : this.getUrlOnFailure();
})
.catch(() => this.getUrlOnFailure());
}
else {
return this.checkRoles();
return checkOrg ? this.checkOrgByAppId(route.params.id) : this.checkRoles();
}
}
@ -44,4 +53,26 @@ export class RolesGuard implements CanActivate{
return this.allowedRoles.length === 0
|| this.authService.hasAnyRole(this.allowedRoles);
}
private checkOrgByAppId(id: string): Promise<boolean | UrlTree> {
if (this.authService.hasAnyRole([ErvuRole.CREATOR, ErvuRole.REVIEWER])) {
return this.httpClient.get("allowed", {
headers: {
'app-number': id,
'check-parents': (!this.authService.hasRole(ErvuRole.CREATOR)).toString()
},
observe: 'response'
})
.toPromise()
.then(response => {
return response.body ? true : this.getUrlOnFailure();
})
.catch(() => this.getUrlOnFailure());
}
else if (this.authService.hasRole(ErvuRole.APPROVER)) {
return Promise.resolve(true);
}
return Promise.resolve(this.getUrlOnFailure());
}
}