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>
<tag>HEAD</tag>
</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>
<dependency>
<groupId>eu.dnetlib</groupId>
<artifactId>uoa-login-core</artifactId>
<version>2.0.2</version>
<version>2.0.3</version>
</dependency>
<!--swagger-->
<dependency>

View File

@ -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) {

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

View File

@ -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<List<API>> getAll() {
public ResponseEntity<List<APIsByIssuer>> getAll() {
return ResponseEntity.ok(this.service.getAll());
}
@PreAuthorize("hasAnyAuthority('PORTAL_ADMINISTRATOR')")
@RequestMapping(value = "/migrate/accessToken", method = RequestMethod.POST)
public ResponseEntity<List<API>> migrateAccessToken(@RequestBody List<RegisteredAT> registeredATS) {
return ResponseEntity.ok(this.service.migrateAccessToken(registeredATS));
@RequestMapping(value = "/copy", method = RequestMethod.POST)
public ResponseEntity<List<API>> 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);

View File

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

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;
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() {

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();
}
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();

View File

@ -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<RegisteredService,
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> findByClientId(String clientId);
Optional<RegisteredService> findByClientIdAndIssuer(String clientId, String issuer);
List<RegisteredService> findAllByIssuerOrderByOwnerAsc(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.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<API> 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<APIsByIssuer> getAll() {
List<String> 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<API> migrateAccessToken(List<RegisteredAT> registeredAT) {
List<API> apis = new ArrayList<>();
registeredAT.forEach( element -> {
RegisteredService service = this.dao.findByClientId(element.getClientId()).orElse(null);
if(service != null) {
service.setRegistrationAccessToken(element.getRegistrationAccessToken());
public List<API> copyServices(CopyServices services) {
List<API> 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);
}
}

View File

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