From 79731291b8e335c1c0f6bf0aa3f461db3b13d096 Mon Sep 17 00:00:00 2001 From: "k.triantafyllou" Date: Thu, 27 Jul 2023 15:54:15 +0300 Subject: [PATCH] Change migrate to copyServices and change getAll services in order to return services by issuer. Add HealthController and update login-core --- pom.xml | 8 ++- .../developers/DevelopersAPIApplication.java | 4 +- .../configuration/APIProperties.java | 38 ++++++++++ .../developers/configuration/GlobalVars.java | 31 ++++++++ .../configuration/SwaggerConfig.java | 2 - .../developers/controllers/APIController.java | 13 ++-- .../controllers/HealthController.java | 28 ++++++-- .../dnetlib/developers/dto/APIsByIssuer.java | 31 ++++++++ .../{RegisteredAT.java => CopyService.java} | 4 +- .../dnetlib/developers/dto/CopyServices.java | 27 +++++++ .../entities/RegisteredService.java | 14 ++++ .../repositories/RegisteredServiceDAO.java | 9 ++- .../developers/services/APIService.java | 71 +++++++++++-------- src/main/resources/developers.properties | 3 + 14 files changed, 236 insertions(+), 47 deletions(-) create mode 100644 src/main/java/eu/dnetlib/developers/configuration/APIProperties.java create mode 100644 src/main/java/eu/dnetlib/developers/configuration/GlobalVars.java create mode 100644 src/main/java/eu/dnetlib/developers/dto/APIsByIssuer.java rename src/main/java/eu/dnetlib/developers/dto/{RegisteredAT.java => CopyService.java} (92%) create mode 100644 src/main/java/eu/dnetlib/developers/dto/CopyServices.java diff --git a/pom.xml b/pom.xml index 5b8eb62..c400667 100644 --- a/pom.xml +++ b/pom.xml @@ -14,11 +14,17 @@ scm:git:gitea@code-repo.d4science.org:MaDgIK/developers-api.git HEAD + + UTF-8 + UTF-8 + ${maven.build.timestamp} + E MMM dd HH:mm:ss z yyyy + eu.dnetlib uoa-login-core - 2.0.2 + 2.0.3 diff --git a/src/main/java/eu/dnetlib/developers/DevelopersAPIApplication.java b/src/main/java/eu/dnetlib/developers/DevelopersAPIApplication.java index 3833942..c77984f 100644 --- a/src/main/java/eu/dnetlib/developers/DevelopersAPIApplication.java +++ b/src/main/java/eu/dnetlib/developers/DevelopersAPIApplication.java @@ -1,6 +1,8 @@ package eu.dnetlib.developers; import eu.dnetlib.authentication.configuration.AuthenticationConfiguration; +import eu.dnetlib.developers.configuration.APIProperties; +import eu.dnetlib.developers.configuration.GlobalVars; import eu.dnetlib.developers.configuration.Properties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -16,7 +18,7 @@ import org.springframework.context.annotation.PropertySources; @PropertySource(value = "classpath:dnet-override.properties", ignoreResourceNotFound = true) }) @Import({AuthenticationConfiguration.class}) -@EnableConfigurationProperties({Properties.class}) +@EnableConfigurationProperties({Properties.class, APIProperties.class, GlobalVars.class}) public class DevelopersAPIApplication { public static void main(String[] args) { diff --git a/src/main/java/eu/dnetlib/developers/configuration/APIProperties.java b/src/main/java/eu/dnetlib/developers/configuration/APIProperties.java new file mode 100644 index 0000000..31bbfc0 --- /dev/null +++ b/src/main/java/eu/dnetlib/developers/configuration/APIProperties.java @@ -0,0 +1,38 @@ +package eu.dnetlib.developers.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("api") +public class APIProperties { + + private String title; + private String description; + private String version; + + public APIProperties() { + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } +} diff --git a/src/main/java/eu/dnetlib/developers/configuration/GlobalVars.java b/src/main/java/eu/dnetlib/developers/configuration/GlobalVars.java new file mode 100644 index 0000000..df679ff --- /dev/null +++ b/src/main/java/eu/dnetlib/developers/configuration/GlobalVars.java @@ -0,0 +1,31 @@ +package eu.dnetlib.developers.configuration; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.Date; + +@ConfigurationProperties("developers-api.globalVars") +public class GlobalVars { + public static Date date = new Date(); + private Date buildDate; + private String version; + + public String getBuildDate() { + if(buildDate == null) { + return null; + } + return buildDate.toString(); + } + + public void setBuildDate(Date buildDate) { + this.buildDate = buildDate; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } +} diff --git a/src/main/java/eu/dnetlib/developers/configuration/SwaggerConfig.java b/src/main/java/eu/dnetlib/developers/configuration/SwaggerConfig.java index 494327a..a95385a 100644 --- a/src/main/java/eu/dnetlib/developers/configuration/SwaggerConfig.java +++ b/src/main/java/eu/dnetlib/developers/configuration/SwaggerConfig.java @@ -1,6 +1,4 @@ package eu.dnetlib.developers.configuration; - -import eu.dnetlib.authentication.configuration.APIProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/eu/dnetlib/developers/controllers/APIController.java b/src/main/java/eu/dnetlib/developers/controllers/APIController.java index 8fdd952..f2532b7 100644 --- a/src/main/java/eu/dnetlib/developers/controllers/APIController.java +++ b/src/main/java/eu/dnetlib/developers/controllers/APIController.java @@ -1,7 +1,8 @@ package eu.dnetlib.developers.controllers; -import eu.dnetlib.developers.dto.RegisteredAT; import eu.dnetlib.developers.dto.API; +import eu.dnetlib.developers.dto.APIsByIssuer; +import eu.dnetlib.developers.dto.CopyServices; import eu.dnetlib.developers.dto.ServiceForm; import eu.dnetlib.developers.services.APIService; import org.springframework.beans.factory.annotation.Autowired; @@ -26,14 +27,14 @@ public class APIController { @PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')") @RequestMapping(value = "/all", method = RequestMethod.GET) - public ResponseEntity> getAll() { + public ResponseEntity> getAll() { return ResponseEntity.ok(this.service.getAll()); } @PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')") - @RequestMapping(value = "/migrate/accessToken", method = RequestMethod.POST) - public ResponseEntity> migrateAccessToken(@RequestBody List registeredATS) { - return ResponseEntity.ok(this.service.migrateAccessToken(registeredATS)); + @RequestMapping(value = "/copy", method = RequestMethod.POST) + public ResponseEntity> copyServices(@RequestBody CopyServices services) { + return ResponseEntity.ok(this.service.copyServices(services)); } @@ -55,7 +56,7 @@ public class APIController { return ResponseEntity.ok(this.service.save(form, id)); } - @PreAuthorize("hasAnyAuthority('REGISTERED_USER') && @AuthorizationService.hasPersonalInfo() && @AuthorizationService.isMyService(#id)") + @PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR') || (hasAnyAuthority('REGISTERED_USER') && @AuthorizationService.hasPersonalInfo() && @AuthorizationService.isMyService(#id))") @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE) public ResponseEntity delete(@PathVariable Long id) { this.service.delete(id); diff --git a/src/main/java/eu/dnetlib/developers/controllers/HealthController.java b/src/main/java/eu/dnetlib/developers/controllers/HealthController.java index 0bd9fdb..bf152b6 100644 --- a/src/main/java/eu/dnetlib/developers/controllers/HealthController.java +++ b/src/main/java/eu/dnetlib/developers/controllers/HealthController.java @@ -1,6 +1,7 @@ package eu.dnetlib.developers.controllers; -import eu.dnetlib.authentication.configuration.AuthenticationConfiguration; +import eu.dnetlib.developers.configuration.GlobalVars; +import eu.dnetlib.developers.configuration.Properties; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -9,16 +10,19 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import java.util.HashMap; import java.util.Map; @RestController public class HealthController { private final Logger log = LogManager.getLogger(this.getClass()); - private final AuthenticationConfiguration configuration; + private final Properties properties; + private final GlobalVars globalVars; @Autowired - public HealthController(AuthenticationConfiguration configuration) { - this.configuration = configuration; + public HealthController(Properties properties, GlobalVars globalVars) { + this.properties = properties; + this.globalVars = globalVars; } @RequestMapping(value = {"", "/health_check"}, method = RequestMethod.GET) @@ -30,7 +34,21 @@ public class HealthController { @PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')") @RequestMapping(value = "/health_check/advanced", method = RequestMethod.GET) public Map checkEverything() { - Map response = configuration.getProperties(); + Map response = new HashMap<>(); + response.put("developers.datasource.driver", properties.getDatasource().getDriver()); + response.put("developers.datasource.url", properties.getDatasource().getUrl()); + response.put("developers.datasource.username", properties.getDatasource().getUsername()); + response.put("developers.datasource.password", properties.getDatasource().getPassword()); + response.put("developers.issuer", properties.getIssuer()); + if(eu.dnetlib.authentication.configuration.GlobalVars.date != null) { + response.put("Date of deploy", eu.dnetlib.authentication.configuration.GlobalVars.date.toString()); + } + if(globalVars.getBuildDate() != null) { + response.put("Date of build", globalVars.getBuildDate()); + } + if (globalVars.getVersion() != null) { + response.put("Version", globalVars.getVersion()); + } return response; } } diff --git a/src/main/java/eu/dnetlib/developers/dto/APIsByIssuer.java b/src/main/java/eu/dnetlib/developers/dto/APIsByIssuer.java new file mode 100644 index 0000000..0c0037b --- /dev/null +++ b/src/main/java/eu/dnetlib/developers/dto/APIsByIssuer.java @@ -0,0 +1,31 @@ +package eu.dnetlib.developers.dto; + +import java.util.List; + +public class APIsByIssuer { + String issuer; + List apis; + + public APIsByIssuer() { + } + + public APIsByIssuer(String issuer) { + this.issuer = issuer; + } + + public String getIssuer() { + return issuer; + } + + public void setIssuer(String issuer) { + this.issuer = issuer; + } + + public List getApis() { + return apis; + } + + public void setApis(List apis) { + this.apis = apis; + } +} diff --git a/src/main/java/eu/dnetlib/developers/dto/RegisteredAT.java b/src/main/java/eu/dnetlib/developers/dto/CopyService.java similarity index 92% rename from src/main/java/eu/dnetlib/developers/dto/RegisteredAT.java rename to src/main/java/eu/dnetlib/developers/dto/CopyService.java index 7e12e4c..27e0f15 100644 --- a/src/main/java/eu/dnetlib/developers/dto/RegisteredAT.java +++ b/src/main/java/eu/dnetlib/developers/dto/CopyService.java @@ -2,13 +2,13 @@ package eu.dnetlib.developers.dto; import com.fasterxml.jackson.annotation.JsonProperty; -public class RegisteredAT { +public class CopyService { @JsonProperty("client_id") private String clientId; @JsonProperty("registration_access_token") private String registrationAccessToken; - public RegisteredAT() { + public CopyService() { } public String getClientId() { diff --git a/src/main/java/eu/dnetlib/developers/dto/CopyServices.java b/src/main/java/eu/dnetlib/developers/dto/CopyServices.java new file mode 100644 index 0000000..7474bd9 --- /dev/null +++ b/src/main/java/eu/dnetlib/developers/dto/CopyServices.java @@ -0,0 +1,27 @@ +package eu.dnetlib.developers.dto; + +import java.util.List; + +public class CopyServices { + public String issuer; + public List services; + + public CopyServices() { + } + + public String getIssuer() { + return issuer; + } + + public void setIssuer(String issuer) { + this.issuer = issuer; + } + + public List getServices() { + return services; + } + + public void setServices(List services) { + this.services = services; + } +} diff --git a/src/main/java/eu/dnetlib/developers/entities/RegisteredService.java b/src/main/java/eu/dnetlib/developers/entities/RegisteredService.java index 69a658b..42c7f19 100644 --- a/src/main/java/eu/dnetlib/developers/entities/RegisteredService.java +++ b/src/main/java/eu/dnetlib/developers/entities/RegisteredService.java @@ -39,6 +39,20 @@ public class RegisteredService { this.creationDate = new Date(); } + public RegisteredService(RegisteredService service, String registrationAccessToken, String issuer) { + this.clientId = service.getClientId(); + this.owner = service.getOwner(); + this.name = service.getName(); + this.creationDate = new Date(); + this.registrationAccessToken = registrationAccessToken; + this.keyType = service.getKeyType(); + this.url = service.getUrl(); + this.description = service.getDescription(); + this.frequency = service.getFrequency(); + this.target = service.getTarget(); + this.issuer = issuer; + } + public void setService(ServiceForm form, ServiceResponse response) { this.clientId = response.getClientId(); this.name = form.getName(); diff --git a/src/main/java/eu/dnetlib/developers/repositories/RegisteredServiceDAO.java b/src/main/java/eu/dnetlib/developers/repositories/RegisteredServiceDAO.java index 9ee45f7..285a3ce 100644 --- a/src/main/java/eu/dnetlib/developers/repositories/RegisteredServiceDAO.java +++ b/src/main/java/eu/dnetlib/developers/repositories/RegisteredServiceDAO.java @@ -1,7 +1,9 @@ package eu.dnetlib.developers.repositories; import eu.dnetlib.developers.entities.RegisteredService; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import java.util.List; @@ -12,9 +14,14 @@ public interface RegisteredServiceDAO extends CrudRepository findAll(); + @Query("select distinct rs.issuer from RegisteredService rs where rs.issuer != :#{#issuer}") + List findAllIssuersExceptActive(@Param("issuer") String issuer); + Optional findById(Long id); - Optional findByClientId(String clientId); + Optional findByClientIdAndIssuer(String clientId, String issuer); + + List findAllByIssuerOrderByOwnerAsc(String issuer); List findAllByOwnerAndIssuerOrderByCreationDateAsc(String owner, String issuer); } diff --git a/src/main/java/eu/dnetlib/developers/services/APIService.java b/src/main/java/eu/dnetlib/developers/services/APIService.java index 4d7d496..82066a0 100644 --- a/src/main/java/eu/dnetlib/developers/services/APIService.java +++ b/src/main/java/eu/dnetlib/developers/services/APIService.java @@ -16,16 +16,15 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Service() public class APIService { - private RegisteredServiceDAO dao; - private RestTemplate template; - private String issuer; + private final RegisteredServiceDAO dao; + private final RestTemplate template; + private final String issuer; @Autowired public APIService(RegisteredServiceDAO dao, RestTemplate template, Properties properties) { @@ -34,12 +33,18 @@ public class APIService { this.issuer = properties.getIssuer(); } - public List getAll() { - return this.dao.findAll().stream().map(service -> { - API details = new API(); - details.setService(service); - details.setDetails(this.readService(service.getClientId(), service.getRegistrationAccessToken())); - return details; + public List getAll() { + List issuers = new ArrayList<>(Collections.singletonList(this.issuer)); + issuers.addAll(this.dao.findAllIssuersExceptActive(this.issuer)); + return issuers.stream().map(issuer -> { + APIsByIssuer api = new APIsByIssuer(issuer); + api.setApis(this.dao.findAllByIssuerOrderByOwnerAsc(issuer).stream().map(service -> { + API details = new API(); + details.setService(service); + details.setDetails(this.readService(service.getClientId(), service.getRegistrationAccessToken())); + return details; + }).collect(Collectors.toList())); + return api; }).collect(Collectors.toList()); } @@ -53,15 +58,21 @@ public class APIService { }).collect(Collectors.toList()); } - public List migrateAccessToken(List registeredAT) { - List apis = new ArrayList<>(); - registeredAT.forEach( element -> { - RegisteredService service = this.dao.findByClientId(element.getClientId()).orElse(null); - if(service != null) { - service.setRegistrationAccessToken(element.getRegistrationAccessToken()); + public List copyServices(CopyServices services) { + List apis = this.dao.findAllByIssuerOrderByOwnerAsc(this.issuer).stream().map(service -> { + API details = new API(); + details.setService(service); + details.setDetails(this.readService(service.getClientId(), service.getRegistrationAccessToken())); + return details; + }).collect(Collectors.toList()); + services.getServices().forEach(element -> { + RegisteredService service = this.dao.findByClientIdAndIssuer(element.getClientId(), services.getIssuer()).orElse(null); + RegisteredService newService = this.dao.findByClientIdAndIssuer(element.getClientId(), this.issuer).orElse(null); + if (service != null && newService == null) { + newService = new RegisteredService(service, element.getRegistrationAccessToken(), this.issuer); API api = new API(); - api.setService(this.dao.save(service)); - api.setDetails(this.readService(service.getClientId(), service.getRegistrationAccessToken())); + api.setService(this.dao.save(newService)); + api.setDetails(this.readService(newService.getClientId(), service.getRegistrationAccessToken())); apis.add(api); } }); @@ -72,9 +83,9 @@ public class APIService { ServiceRequest request; API api = new API(); OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - if(id != null) { + if (id != null) { RegisteredService service = this.dao.findById(id).orElse(null); - if(service == null) { + if (service == null) { throw new EntityNotFoundException("Service with id " + id + " does not exist."); } api.setService(service); @@ -83,16 +94,16 @@ public class APIService { api.setService(new RegisteredService(authentication.getSub(), issuer)); } String keyType = form.getKeyType(); - if(keyType != null && keyType.equals("uri")) { - if(form.getUri() == null) { + if (keyType != null && keyType.equals("uri")) { + if (form.getUri() == null) { throw new EntityMissingException("Uri is required in this type of key"); } request = ServiceRequest.createServiceRequest(api.getService().getClientId(), form.getName(), form.getLogoURL(), authentication.getUserInfo().getEmail(), form.getUri()); - } else if(keyType != null && keyType.equals("value")) { + } else if (keyType != null && keyType.equals("value")) { Gson gson = new GsonBuilder().registerTypeAdapter(Jwks.class, new JwksDeserializer()).create(); String jwksSet = String.format("{\"keys\":[%s]}", form.getValue()); form.setJwks(gson.fromJson(jwksSet, Jwks.class)); - if(!form.getJwks().isValid()) { + if (!form.getJwks().isValid()) { throw new EntityMissingException("Jwks value is not valid"); } request = ServiceRequest.createServiceRequest(api.getService().getClientId(), form.getName(), form.getLogoURL(), authentication.getUserInfo().getEmail(), form.getJwks()); @@ -100,10 +111,10 @@ public class APIService { request = ServiceRequest.createServiceRequest(api.getService().getClientId(), form.getName(), form.getLogoURL(), authentication.getUserInfo().getEmail()); } ServiceResponse response; - if(api.getService().getClientId() != null) { + if (api.getService().getClientId() != null) { response = this.updateService(api.getService().getClientId(), request, api.getService().getRegistrationAccessToken()); } else { - if(this.dao.findAllByOwnerAndIssuerOrderByCreationDateAsc(authentication.getSub(), issuer).size() < 5) { + if (this.dao.findAllByOwnerAndIssuerOrderByCreationDateAsc(authentication.getSub(), issuer).size() < 5) { response = this.createService(request); } else { throw new ForbiddenException("You are not allowed to own more than 5 services."); @@ -121,10 +132,12 @@ public class APIService { public void delete(Long id) { RegisteredService service = this.dao.findById(id).orElse(null); - if(service == null) { + if (service == null) { throw new EntityNotFoundException("Service with id " + id + " does not exist."); } else { - this.deleteService(service.getClientId(), service.getRegistrationAccessToken()); + if(readService(service.getClientId(), service.getRegistrationAccessToken()) != null) { + this.deleteService(service.getClientId(), service.getRegistrationAccessToken()); + } this.dao.delete(id); } } diff --git a/src/main/resources/developers.properties b/src/main/resources/developers.properties index 12c5a2d..2efc849 100644 --- a/src/main/resources/developers.properties +++ b/src/main/resources/developers.properties @@ -10,3 +10,6 @@ spring.jpa.hibernate.ddl-auto=none api.title = Developers API api.description = Developers API includes authentication methods and provides functionalities to manage OpenAIRE Dynamic AAI APIs. api.version = ${project.version} + +developers-api.global-vars.buildDate=@timestamp@ +developers-api.global-vars.version=@project.version@