Change migrate to copyServices and change getAll services in order to return services by issuer. Add HealthController and update login-core

This commit is contained in:
Konstantinos Triantafyllou 2023-07-27 15:54:15 +03:00
parent 7589427871
commit 79731291b8
14 changed files with 236 additions and 47 deletions

View File

@ -14,11 +14,17 @@
<developerConnection>scm:git:gitea@code-repo.d4science.org:MaDgIK/developers-api.git</developerConnection> <developerConnection>scm:git:gitea@code-repo.d4science.org:MaDgIK/developers-api.git</developerConnection>
<tag>HEAD</tag> <tag>HEAD</tag>
</scm> </scm>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>E MMM dd HH:mm:ss z yyyy</maven.build.timestamp.format>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>eu.dnetlib</groupId> <groupId>eu.dnetlib</groupId>
<artifactId>uoa-login-core</artifactId> <artifactId>uoa-login-core</artifactId>
<version>2.0.2</version> <version>2.0.3</version>
</dependency> </dependency>
<!--swagger--> <!--swagger-->
<dependency> <dependency>

View File

@ -1,6 +1,8 @@
package eu.dnetlib.developers; package eu.dnetlib.developers;
import eu.dnetlib.authentication.configuration.AuthenticationConfiguration; 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 eu.dnetlib.developers.configuration.Properties;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -16,7 +18,7 @@ import org.springframework.context.annotation.PropertySources;
@PropertySource(value = "classpath:dnet-override.properties", ignoreResourceNotFound = true) @PropertySource(value = "classpath:dnet-override.properties", ignoreResourceNotFound = true)
}) })
@Import({AuthenticationConfiguration.class}) @Import({AuthenticationConfiguration.class})
@EnableConfigurationProperties({Properties.class}) @EnableConfigurationProperties({Properties.class, APIProperties.class, GlobalVars.class})
public class DevelopersAPIApplication { public class DevelopersAPIApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,6 +1,4 @@
package eu.dnetlib.developers.configuration; package eu.dnetlib.developers.configuration;
import eu.dnetlib.authentication.configuration.APIProperties;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

View File

@ -1,7 +1,8 @@
package eu.dnetlib.developers.controllers; package eu.dnetlib.developers.controllers;
import eu.dnetlib.developers.dto.RegisteredAT;
import eu.dnetlib.developers.dto.API; 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.dto.ServiceForm;
import eu.dnetlib.developers.services.APIService; import eu.dnetlib.developers.services.APIService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -26,14 +27,14 @@ public class APIController {
@PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')") @PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')")
@RequestMapping(value = "/all", method = RequestMethod.GET) @RequestMapping(value = "/all", method = RequestMethod.GET)
public ResponseEntity<List<API>> getAll() { public ResponseEntity<List<APIsByIssuer>> getAll() {
return ResponseEntity.ok(this.service.getAll()); return ResponseEntity.ok(this.service.getAll());
} }
@PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')") @PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')")
@RequestMapping(value = "/migrate/accessToken", method = RequestMethod.POST) @RequestMapping(value = "/copy", method = RequestMethod.POST)
public ResponseEntity<List<API>> migrateAccessToken(@RequestBody List<RegisteredAT> registeredATS) { public ResponseEntity<List<API>> copyServices(@RequestBody CopyServices services) {
return ResponseEntity.ok(this.service.migrateAccessToken(registeredATS)); return ResponseEntity.ok(this.service.copyServices(services));
} }
@ -55,7 +56,7 @@ public class APIController {
return ResponseEntity.ok(this.service.save(form, id)); 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) @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
public ResponseEntity<?> delete(@PathVariable Long id) { public ResponseEntity<?> delete(@PathVariable Long id) {
this.service.delete(id); this.service.delete(id);

View File

@ -1,6 +1,7 @@
package eu.dnetlib.developers.controllers; 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.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; 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.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
@RestController @RestController
public class HealthController { public class HealthController {
private final Logger log = LogManager.getLogger(this.getClass()); private final Logger log = LogManager.getLogger(this.getClass());
private final AuthenticationConfiguration configuration; private final Properties properties;
private final GlobalVars globalVars;
@Autowired @Autowired
public HealthController(AuthenticationConfiguration configuration) { public HealthController(Properties properties, GlobalVars globalVars) {
this.configuration = configuration; this.properties = properties;
this.globalVars = globalVars;
} }
@RequestMapping(value = {"", "/health_check"}, method = RequestMethod.GET) @RequestMapping(value = {"", "/health_check"}, method = RequestMethod.GET)
@ -30,7 +34,21 @@ public class HealthController {
@PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')") @PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')")
@RequestMapping(value = "/health_check/advanced", method = RequestMethod.GET) @RequestMapping(value = "/health_check/advanced", method = RequestMethod.GET)
public Map<String, String> checkEverything() { public Map<String, String> checkEverything() {
Map<String, String> response = configuration.getProperties(); Map<String, String> 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; return response;
} }
} }

View File

@ -0,0 +1,31 @@
package eu.dnetlib.developers.dto;
import java.util.List;
public class APIsByIssuer {
String issuer;
List<API> 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<API> getApis() {
return apis;
}
public void setApis(List<API> apis) {
this.apis = apis;
}
}

View File

@ -2,13 +2,13 @@ package eu.dnetlib.developers.dto;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
public class RegisteredAT { public class CopyService {
@JsonProperty("client_id") @JsonProperty("client_id")
private String clientId; private String clientId;
@JsonProperty("registration_access_token") @JsonProperty("registration_access_token")
private String registrationAccessToken; private String registrationAccessToken;
public RegisteredAT() { public CopyService() {
} }
public String getClientId() { public String getClientId() {

View File

@ -0,0 +1,27 @@
package eu.dnetlib.developers.dto;
import java.util.List;
public class CopyServices {
public String issuer;
public List<CopyService> services;
public CopyServices() {
}
public String getIssuer() {
return issuer;
}
public void setIssuer(String issuer) {
this.issuer = issuer;
}
public List<CopyService> getServices() {
return services;
}
public void setServices(List<CopyService> services) {
this.services = services;
}
}

View File

@ -39,6 +39,20 @@ public class RegisteredService {
this.creationDate = new Date(); 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) { public void setService(ServiceForm form, ServiceResponse response) {
this.clientId = response.getClientId(); this.clientId = response.getClientId();
this.name = form.getName(); this.name = form.getName();

View File

@ -1,7 +1,9 @@
package eu.dnetlib.developers.repositories; package eu.dnetlib.developers.repositories;
import eu.dnetlib.developers.entities.RegisteredService; import eu.dnetlib.developers.entities.RegisteredService;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
@ -12,9 +14,14 @@ public interface RegisteredServiceDAO extends CrudRepository<RegisteredService,
List<RegisteredService> findAll(); List<RegisteredService> findAll();
@Query("select distinct rs.issuer from RegisteredService rs where rs.issuer != :#{#issuer}")
List<String> findAllIssuersExceptActive(@Param("issuer") String issuer);
Optional<RegisteredService> findById(Long id); Optional<RegisteredService> findById(Long id);
Optional<RegisteredService> findByClientId(String clientId); Optional<RegisteredService> findByClientIdAndIssuer(String clientId, String issuer);
List<RegisteredService> findAllByIssuerOrderByOwnerAsc(String issuer);
List<RegisteredService> findAllByOwnerAndIssuerOrderByCreationDateAsc(String owner, String issuer); List<RegisteredService> findAllByOwnerAndIssuerOrderByCreationDateAsc(String owner, String issuer);
} }

View File

@ -16,16 +16,15 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service() @Service()
public class APIService { public class APIService {
private RegisteredServiceDAO dao; private final RegisteredServiceDAO dao;
private RestTemplate template; private final RestTemplate template;
private String issuer; private final String issuer;
@Autowired @Autowired
public APIService(RegisteredServiceDAO dao, RestTemplate template, Properties properties) { public APIService(RegisteredServiceDAO dao, RestTemplate template, Properties properties) {
@ -34,12 +33,18 @@ public class APIService {
this.issuer = properties.getIssuer(); this.issuer = properties.getIssuer();
} }
public List<API> getAll() { public List<APIsByIssuer> getAll() {
return this.dao.findAll().stream().map(service -> { List<String> issuers = new ArrayList<>(Collections.singletonList(this.issuer));
API details = new API(); issuers.addAll(this.dao.findAllIssuersExceptActive(this.issuer));
details.setService(service); return issuers.stream().map(issuer -> {
details.setDetails(this.readService(service.getClientId(), service.getRegistrationAccessToken())); APIsByIssuer api = new APIsByIssuer(issuer);
return details; 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()); }).collect(Collectors.toList());
} }
@ -53,15 +58,21 @@ public class APIService {
}).collect(Collectors.toList()); }).collect(Collectors.toList());
} }
public List<API> migrateAccessToken(List<RegisteredAT> registeredAT) { public List<API> copyServices(CopyServices services) {
List<API> apis = new ArrayList<>(); List<API> apis = this.dao.findAllByIssuerOrderByOwnerAsc(this.issuer).stream().map(service -> {
registeredAT.forEach( element -> { API details = new API();
RegisteredService service = this.dao.findByClientId(element.getClientId()).orElse(null); details.setService(service);
if(service != null) { details.setDetails(this.readService(service.getClientId(), service.getRegistrationAccessToken()));
service.setRegistrationAccessToken(element.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 api = new API();
api.setService(this.dao.save(service)); api.setService(this.dao.save(newService));
api.setDetails(this.readService(service.getClientId(), service.getRegistrationAccessToken())); api.setDetails(this.readService(newService.getClientId(), service.getRegistrationAccessToken()));
apis.add(api); apis.add(api);
} }
}); });
@ -72,9 +83,9 @@ public class APIService {
ServiceRequest request; ServiceRequest request;
API api = new API(); API api = new API();
OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); OIDCAuthenticationToken authentication = (OIDCAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
if(id != null) { if (id != null) {
RegisteredService service = this.dao.findById(id).orElse(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."); throw new EntityNotFoundException("Service with id " + id + " does not exist.");
} }
api.setService(service); api.setService(service);
@ -83,16 +94,16 @@ public class APIService {
api.setService(new RegisteredService(authentication.getSub(), issuer)); api.setService(new RegisteredService(authentication.getSub(), issuer));
} }
String keyType = form.getKeyType(); String keyType = form.getKeyType();
if(keyType != null && keyType.equals("uri")) { if (keyType != null && keyType.equals("uri")) {
if(form.getUri() == null) { if (form.getUri() == null) {
throw new EntityMissingException("Uri is required in this type of key"); 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()); 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(); Gson gson = new GsonBuilder().registerTypeAdapter(Jwks.class, new JwksDeserializer()).create();
String jwksSet = String.format("{\"keys\":[%s]}", form.getValue()); String jwksSet = String.format("{\"keys\":[%s]}", form.getValue());
form.setJwks(gson.fromJson(jwksSet, Jwks.class)); form.setJwks(gson.fromJson(jwksSet, Jwks.class));
if(!form.getJwks().isValid()) { if (!form.getJwks().isValid()) {
throw new EntityMissingException("Jwks value is not valid"); throw new EntityMissingException("Jwks value is not valid");
} }
request = ServiceRequest.createServiceRequest(api.getService().getClientId(), form.getName(), form.getLogoURL(), authentication.getUserInfo().getEmail(), form.getJwks()); 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()); request = ServiceRequest.createServiceRequest(api.getService().getClientId(), form.getName(), form.getLogoURL(), authentication.getUserInfo().getEmail());
} }
ServiceResponse response; ServiceResponse response;
if(api.getService().getClientId() != null) { if (api.getService().getClientId() != null) {
response = this.updateService(api.getService().getClientId(), request, api.getService().getRegistrationAccessToken()); response = this.updateService(api.getService().getClientId(), request, api.getService().getRegistrationAccessToken());
} else { } else {
if(this.dao.findAllByOwnerAndIssuerOrderByCreationDateAsc(authentication.getSub(), issuer).size() < 5) { if (this.dao.findAllByOwnerAndIssuerOrderByCreationDateAsc(authentication.getSub(), issuer).size() < 5) {
response = this.createService(request); response = this.createService(request);
} else { } else {
throw new ForbiddenException("You are not allowed to own more than 5 services."); 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) { public void delete(Long id) {
RegisteredService service = this.dao.findById(id).orElse(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."); throw new EntityNotFoundException("Service with id " + id + " does not exist.");
} else { } else {
this.deleteService(service.getClientId(), service.getRegistrationAccessToken()); if(readService(service.getClientId(), service.getRegistrationAccessToken()) != null) {
this.deleteService(service.getClientId(), service.getRegistrationAccessToken());
}
this.dao.delete(id); this.dao.delete(id);
} }
} }

View File

@ -10,3 +10,6 @@ spring.jpa.hibernate.ddl-auto=none
api.title = Developers API api.title = Developers API
api.description = Developers API includes authentication methods and provides functionalities to manage OpenAIRE Dynamic AAI APIs. api.description = Developers API includes authentication methods and provides functionalities to manage OpenAIRE Dynamic AAI APIs.
api.version = ${project.version} api.version = ${project.version}
developers-api.global-vars.buildDate=@timestamp@
developers-api.global-vars.version=@project.version@