authz changes

This commit is contained in:
Efstratios Giannopoulos 2024-01-04 18:09:09 +02:00
parent 6a077d2b09
commit 1a567c9a81
11 changed files with 61 additions and 222 deletions

View File

@ -59,8 +59,8 @@ public class SecurityConfiguration {
.headers(httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) .headers(httpSecurityHeadersConfigurer -> httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
.addFilterBefore(apiKeyFilter, AbstractPreAuthenticatedProcessingFilter.class) .addFilterBefore(apiKeyFilter, AbstractPreAuthenticatedProcessingFilter.class)
.authorizeHttpRequests(authRequest -> .authorizeHttpRequests(authRequest ->
authRequest.requestMatchers(buildAntPatterns(webSecurityProperties.getAllowedEndpoints())).permitAll() //TODO: Authz authRequest.requestMatchers(buildAntPatterns(webSecurityProperties.getAllowedEndpoints())).anonymous()
.requestMatchers(buildAntPatterns(webSecurityProperties.getAuthorizedEndpoints())).permitAll()) .requestMatchers(buildAntPatterns(webSecurityProperties.getAuthorizedEndpoints())).authenticated())
.sessionManagement( sessionManagementConfigurer-> sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.NEVER)) .sessionManagement( sessionManagementConfigurer-> sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.NEVER))
.oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver)); .oauth2ResourceServer(oauth2 -> oauth2.authenticationManagerResolver(authenticationManagerResolver));
return tempHttp.build(); return tempHttp.build();

View File

@ -1,60 +0,0 @@
package eu.eudat.controllers;
import eu.eudat.authorization.Permission;
import eu.eudat.logic.managers.ContactEmailManager;
import eu.eudat.models.data.ContactEmail.ContactEmailModel;
import eu.eudat.models.data.ContactEmail.PublicContactEmailModel;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.types.ApiMessageCode;
import gr.cite.commons.web.authz.service.AuthorizationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.transaction.Transactional;
@RestController
@CrossOrigin
@RequestMapping(value = "api/contactEmail")
public class ContactEmail {
private static final Logger logger = LoggerFactory.getLogger(ContactEmail.class);
private ContactEmailManager contactEmailManager;
private final AuthorizationService authorizationService;
public ContactEmail(ContactEmailManager contactEmailManager, AuthorizationService authorizationService) {
this.contactEmailManager = contactEmailManager;
this.authorizationService = authorizationService;
}
@Transactional
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
public @ResponseBody
ResponseEntity sendContactEmail(@RequestBody ContactEmailModel contactEmailModel) {
this.authorizationService.authorizeForce(Permission.AuthenticatedRole);
try {
this.contactEmailManager.emailValidation(contactEmailModel);
this.contactEmailManager.sendContactEmail(contactEmailModel);
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE));
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message(ex.getMessage()));
}
}
@Transactional
@RequestMapping(method = RequestMethod.POST, path = "public", consumes = "application/x-www-form-urlencoded", produces = "application/json")
public @ResponseBody
ResponseEntity sendContactEmailNoAuth(@ModelAttribute PublicContactEmailModel contactEmailModel) {
try {
this.contactEmailManager.sendContactEmailNoAuth(contactEmailModel);
return ResponseEntity.status(HttpStatus.NO_CONTENT).body(new ResponseItem().status(ApiMessageCode.SUCCESS_MESSAGE));
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem().status(ApiMessageCode.ERROR_MESSAGE).message(ex.getMessage()));
}
}
}

View File

@ -1,62 +0,0 @@
package eu.eudat.controllers;
import eu.eudat.authorization.Permission;
import eu.eudat.models.data.helpers.responses.ResponseItem;
import eu.eudat.service.storage.StorageFileService;
import eu.eudat.types.ApiMessageCode;
import gr.cite.commons.web.authz.service.AuthorizationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.*;
@RestController
@CrossOrigin
@RequestMapping(value = {"/api/language/"})
public class LanguageController {
private Environment environment;
private final AuthorizationService authorizationService;
private final StorageFileService storageFileService;
@Autowired
public LanguageController(Environment environment, AuthorizationService authorizationService, StorageFileService storageFileService) {
this.environment = environment;
this.authorizationService = authorizationService;
this.storageFileService = storageFileService;
}
@RequestMapping(value = "update/{lang}", method = RequestMethod.POST)
public @ResponseBody
ResponseEntity<ResponseItem<String>> updateLang(@PathVariable String lang, @RequestBody String json) throws Exception {
this.authorizationService.authorizeForce(Permission.EditLanguage);
this.storageFileService.setLanguage(lang, lang.getBytes());
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<String>().status(ApiMessageCode.SUCCESS_MESSAGE).message("Updated").payload("Updated"));
}
@RequestMapping(value = "{lang}", method = RequestMethod.GET)
public ResponseEntity getLanguage(@PathVariable String lang) throws IOException {
this.authorizationService.authorizeForce(Permission.BrowseLanguage);
File file = this.storageFileService.getLanguageFileName(lang);
byte[] content = this.storageFileService.getLanguage(lang);
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentLength(content.length);
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
responseHeaders.set("Content-Disposition", "attachment;filename=" + file.getName());
responseHeaders.set("Access-Control-Expose-Headers", "Content-Disposition");
responseHeaders.get("Access-Control-Expose-Headers").add("Content-Type");
return new ResponseEntity<>(content, responseHeaders, HttpStatus.OK);
}
}

View File

@ -13,7 +13,6 @@ import eu.eudat.model.result.QueryResult;
import eu.eudat.query.LanguageQuery; import eu.eudat.query.LanguageQuery;
import eu.eudat.query.lookup.LanguageLookup; import eu.eudat.query.lookup.LanguageLookup;
import eu.eudat.service.language.LanguageService; import eu.eudat.service.language.LanguageService;
import gr.cite.commons.web.authz.service.AuthorizationService;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.censor.CensorFactory; import gr.cite.tools.data.censor.CensorFactory;
@ -41,10 +40,10 @@ import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@RestController @RestController
@RequestMapping(path = {"api/v2/language"}) @RequestMapping(path = {"api/language"})
public class LanguageV2Controller { public class LanguageController {
private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(LanguageV2Controller.class)); private static final LoggerService logger = new LoggerService(LoggerFactory.getLogger(LanguageController.class));
private final BuilderFactory builderFactory; private final BuilderFactory builderFactory;
@ -56,24 +55,21 @@ public class LanguageV2Controller {
private final MessageSource messageSource; private final MessageSource messageSource;
private final AuthorizationService authorizationService;
private final LanguageService languageService; private final LanguageService languageService;
@Autowired @Autowired
public LanguageV2Controller( public LanguageController(
BuilderFactory builderFactory, BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
CensorFactory censorFactory, CensorFactory censorFactory,
QueryFactory queryFactory, QueryFactory queryFactory,
MessageSource messageSource, AuthorizationService authorizationService, MessageSource messageSource,
LanguageService languageService) { LanguageService languageService) {
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.auditService = auditService; this.auditService = auditService;
this.censorFactory = censorFactory; this.censorFactory = censorFactory;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.messageSource = messageSource; this.messageSource = messageSource;
this.authorizationService = authorizationService;
this.languageService = languageService; this.languageService = languageService;
} }
@ -112,7 +108,7 @@ public class LanguageV2Controller {
return model; return model;
} }
@GetMapping("code/{code}") @GetMapping("public/code/{code}")
public Language get(@PathVariable("code") String code, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, IOException { public Language get(@PathVariable("code") String code, FieldSet fieldSet) throws MyApplicationException, MyForbiddenException, MyNotFoundException, IOException {
logger.debug(new MapLogEntry("retrieving" + Language.class.getSimpleName()).And("code", code).And("fields", fieldSet)); logger.debug(new MapLogEntry("retrieving" + Language.class.getSimpleName()).And("code", code).And("fields", fieldSet));
@ -135,7 +131,7 @@ public class LanguageV2Controller {
return model; return model;
} }
@PostMapping("available-languages") @PostMapping("public/available-languages")
public QueryResult<String> queryLanguageCodes(@RequestBody LanguageLookup lookup) { public QueryResult<String> queryLanguageCodes(@RequestBody LanguageLookup lookup) {
logger.debug("querying {}", Language.class.getSimpleName()); logger.debug("querying {}", Language.class.getSimpleName());

View File

@ -1,69 +0,0 @@
package eu.eudat.logic.managers;
import eu.eudat.commons.scope.user.UserScope;
import eu.eudat.data.UserEntity;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.model.UserContactInfo;
import eu.eudat.models.data.ContactEmail.ContactEmailModel;
import eu.eudat.models.data.ContactEmail.PublicContactEmailModel;
import eu.eudat.query.UserContactInfoQuery;
import eu.eudat.query.UserQuery;
import gr.cite.tools.data.query.Ordering;
import gr.cite.tools.data.query.QueryFactory;
import org.springframework.core.env.Environment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import jakarta.mail.MessagingException;
import javax.management.InvalidApplicationException;
@Component
public class ContactEmailManager {
private ApiContext apiContext;
private Environment environment;
private final UserScope userScope;
private final QueryFactory queryFactory;
@Autowired
public ContactEmailManager(ApiContext apiContext, Environment environment, UserScope userScope, QueryFactory queryFactory) {
this.apiContext = apiContext;
this.environment = environment;
this.userScope = userScope;
this.queryFactory = queryFactory;
}
public void sendContactEmail(ContactEmailModel contactEmailModel) throws MessagingException, InvalidApplicationException {
// UserEntity user = this.queryFactory.query(UserQuery.class).ids(this.userScope.getUserId()).first();
// SimpleMail mail = new SimpleMail();
// UserContactInfoQuery query = this.queryFactory.query(UserContactInfoQuery.class).userIds(user.getId());
// query.setOrder(new Ordering().addAscending(UserContactInfo._ordinal));
// String enrichedMail = contactEmailModel.getDescription() + "\n\n" + "Send by user: " + query.first().getValue() ;
// mail.setSubject(contactEmailModel.getSubject());
// mail.setTo(environment.getProperty("contact_email.mail"));
// mail.setContent(enrichedMail);
// mail.setFrom(query.first().getValue());
//
// apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail);
}
public void sendContactEmailNoAuth(PublicContactEmailModel contactEmailModel) throws MessagingException {
// SimpleMail mail = new SimpleMail();
// String enrichedMail = contactEmailModel.getMessage() + "\n\n" + "Send by user: " + contactEmailModel.getEmail() ;
// mail.setSubject(contactEmailModel.getAffiliation());
// mail.setTo(environment.getProperty("contact_email.mail"));
// mail.setContent(enrichedMail);
// mail.setFrom(contactEmailModel.getEmail());
//
// apiContext.getUtilitiesService().getMailService().sendSimpleMail(mail);
}
public void emailValidation(ContactEmailModel contactEmailModel) throws Exception {
if (contactEmailModel.getSubject() == null || contactEmailModel.getSubject().trim().isEmpty()) {
throw new Exception("Subject is empty");
}
if (contactEmailModel.getDescription() == null || contactEmailModel.getDescription().trim().isEmpty()) {
throw new Exception("Description is empty");
}
}
}

View File

@ -2,7 +2,7 @@ web:
security: security:
enabled: true enabled: true
authorized-endpoints: [ api ] authorized-endpoints: [ api ]
allowed-endpoints: [ api/public, api/description/public, api/contact-support/public, api/dashboard/public ] allowed-endpoints: [ api/public, api/description/public, api/language/public, api/contact-support/public, api/dashboard/public ]
idp: idp:
api-key: api-key:
enabled: false enabled: false

View File

@ -7,6 +7,8 @@ import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service'; import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
@Injectable() @Injectable()
export class DashboardService { export class DashboardService {
@ -33,6 +35,10 @@ export class DashboardService {
getPublicDashboardStatistics(): Observable<DashboardStatistics> { getPublicDashboardStatistics(): Observable<DashboardStatistics> {
const url = `${this.apiBase}/public/get-statistics`; const url = `${this.apiBase}/public/get-statistics`;
return this.http.get<DashboardStatistics>(url).pipe(catchError((error: any) => throwError(error))); const params = new BaseHttpParams();
params.interceptorContext = {
excludedInterceptors: [InterceptorType.AuthToken]
};
return this.http.get<DashboardStatistics>(url, { params: params }).pipe(catchError((error: any) => throwError(error)));
} }
} }

View File

@ -1,4 +1,4 @@
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { HttpClient, HttpHeaders, HttpParamsOptions, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { IsActive } from '@app/core/common/enum/is-active.enum'; import { IsActive } from '@app/core/common/enum/is-active.enum';
import { Description, DescriptionPersist, DescriptionStatusPersist, PublicDescription } from '@app/core/model/description/description'; import { Description, DescriptionPersist, DescriptionStatusPersist, PublicDescription } from '@app/core/model/description/description';
@ -14,6 +14,8 @@ import { nameof } from 'ts-simple-nameof';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service'; import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { FileFormat } from '@app/core/model/file/file-format.model'; import { FileFormat } from '@app/core/model/file/file-format.model';
import { BaseHttpParams } from '@common/http/base-http-params';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
@Injectable() @Injectable()
export class DescriptionService { export class DescriptionService {
@ -32,15 +34,24 @@ export class DescriptionService {
publicQuery(q: DescriptionLookup): Observable<QueryResult<PublicDescription>> { publicQuery(q: DescriptionLookup): Observable<QueryResult<PublicDescription>> {
const url = `${this.apiBase}/public/query`; const url = `${this.apiBase}/public/query`;
return this.http.post<QueryResult<PublicDescription>>(url, q).pipe(catchError((error: any) => throwError(error))); const params = new BaseHttpParams();
params.interceptorContext = {
excludedInterceptors: [InterceptorType.AuthToken]
};
return this.http.post<QueryResult<PublicDescription>>(url, q, { params: params }).pipe(catchError((error: any) => throwError(error)));
} }
getSingle(id: Guid, reqFields: string[] = []): Observable<Description> { getSingle(id: Guid, reqFields: string[] = []): Observable<Description> {
const url = `${this.apiBase}/${id}`; const url = `${this.apiBase}/${id}`;
const options = { params: { f: reqFields } }; const options: HttpParamsOptions = { fromObject: { f: reqFields } };
let params: BaseHttpParams = new BaseHttpParams(options);
params.interceptorContext = {
excludedInterceptors: [InterceptorType.AuthToken]
};
return this.http return this.http
.get<Description>(url, options).pipe( .get<Description>(url, { params: params }).pipe(
catchError((error: any) => throwError(error))); catchError((error: any) => throwError(error)));
} }

View File

@ -1,4 +1,4 @@
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; import { HttpClient, HttpHeaders, HttpParamsOptions, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DmpUserRole } from '@app/core/common/enum/dmp-user-role'; import { DmpUserRole } from '@app/core/common/enum/dmp-user-role';
@ -52,10 +52,15 @@ export class DmpService {
getPublicSingle(id: Guid, reqFields: string[] = []): Observable<Dmp> { //TODO: add this to backend. getPublicSingle(id: Guid, reqFields: string[] = []): Observable<Dmp> { //TODO: add this to backend.
const url = `${this.apiBase}/public/${id}`; const url = `${this.apiBase}/public/${id}`;
const options = { params: { f: reqFields } }; const options: HttpParamsOptions = { fromObject: { f: reqFields } };
let params: BaseHttpParams = new BaseHttpParams(options);
params.interceptorContext = {
excludedInterceptors: [InterceptorType.AuthToken]
};
return this.http return this.http
.get<Dmp>(url, options).pipe( .get<Dmp>(url, { params: params }).pipe(
catchError((error: any) => throwError(error))); catchError((error: any) => throwError(error)));
} }
@ -219,4 +224,4 @@ export class DmpService {
isDmpOwner(dmpUsers: DmpUser[]): Boolean { isDmpOwner(dmpUsers: DmpUser[]): Boolean {
return this.getCurrentUserRolesInDmp(dmpUsers).includes(DmpUserRole.Owner); return this.getCurrentUserRolesInDmp(dmpUsers).includes(DmpUserRole.Owner);
} }
} }

View File

@ -12,6 +12,9 @@ import { catchError, map } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service'; import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { InterceptorType } from '@common/http/interceptors/interceptor-type';
import { BaseHttpParams } from '@common/http/base-http-params';
import { HttpParamsOptions } from '@angular/common/http';
@Injectable() @Injectable()
export class LanguageHttpService { export class LanguageHttpService {
@ -19,7 +22,7 @@ export class LanguageHttpService {
constructor(private http: BaseHttpV2Service, private configurationService: ConfigurationService, private filterService: FilterService) { constructor(private http: BaseHttpV2Service, private configurationService: ConfigurationService, private filterService: FilterService) {
} }
private get apiBase(): string { return `${this.configurationService.server}v2/language`; } private get apiBase(): string { return `${this.configurationService.server}language`; }
query(q: LanguageLookup): Observable<QueryResult<Language>> { query(q: LanguageLookup): Observable<QueryResult<Language>> {
const url = `${this.apiBase}/query`; const url = `${this.apiBase}/query`;
@ -36,17 +39,26 @@ export class LanguageHttpService {
} }
getSingleWithCode(code: string, reqFields: string[] = []): Observable<Language> { getSingleWithCode(code: string, reqFields: string[] = []): Observable<Language> {
const url = `${this.apiBase}/code/${code}`; const url = `${this.apiBase}/public/code/${code}`;
const options = { params: { f: reqFields } }; const options: HttpParamsOptions = { fromObject: { f: reqFields } };
let params: BaseHttpParams = new BaseHttpParams(options);
params.interceptorContext = {
excludedInterceptors: [InterceptorType.AuthToken]
};
return this.http return this.http
.get<Language>(url, options).pipe( .get<Language>(url, { params: params }).pipe(
catchError((error: any) => throwError(error))); catchError((error: any) => throwError(error)));
} }
queryAvailableCodes(q: LanguageLookup): Observable<QueryResult<string>> { queryAvailableCodes(q: LanguageLookup): Observable<QueryResult<string>> {
const url = `${this.apiBase}/available-languages`; const url = `${this.apiBase}/public/available-languages`;
return this.http.post<QueryResult<string>>(url, q).pipe(catchError((error: any) => throwError(error))); const params = new BaseHttpParams();
params.interceptorContext = {
excludedInterceptors: [InterceptorType.AuthToken]
};
return this.http.post<QueryResult<string>>(url, q, { params: params }).pipe(catchError((error: any) => throwError(error)));
} }
persist(item: LanguagePersist): Observable<Language> { persist(item: LanguagePersist): Observable<Language> {
@ -104,4 +116,4 @@ export class LanguageHttpService {
if (like) { lookup.like = this.filterService.transformLike(like); } if (like) { lookup.like = this.filterService.transformLike(like); }
return lookup; return lookup;
} }
} }

View File

@ -14,7 +14,7 @@ export class TranslateServerLoader implements TranslateLoader {
} }
getTranslation(lang: string): Observable<any> { getTranslation(lang: string): Observable<any> {
return this.languageHttpService.getSingleWithCode(lang, [ return this.languageHttpService.getSingleWithCode(lang, [
...nameof<Language>(x => x.id), nameof<Language>(x => x.id),
nameof<Language>(x => x.code), nameof<Language>(x => x.code),
nameof<Language>(x => x.payload), nameof<Language>(x => x.payload),
]).pipe(map(x => JSON.parse(x.payload))); ]).pipe(map(x => JSON.parse(x.payload)));