api to export journal logs
This commit is contained in:
parent
3638a0ea84
commit
e4cbfe863b
|
@ -23,9 +23,9 @@ public class MainApplication extends AbstractDnetApp {
|
||||||
@Bean
|
@Bean
|
||||||
public GroupedOpenApi publicApi() {
|
public GroupedOpenApi publicApi() {
|
||||||
return GroupedOpenApi.builder()
|
return GroupedOpenApi.builder()
|
||||||
.group("D-Net Organizations Service APIs")
|
.group("D-Net Organizations Service APIs")
|
||||||
.pathsToMatch("/api/**", "/oa_api/**")
|
.pathsToMatch("/api/**", "/oa_api/**", "/public-api/**")
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -44,28 +44,28 @@ public class MockSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
http.headers().frameOptions().sameOrigin();
|
http.headers().frameOptions().sameOrigin();
|
||||||
|
|
||||||
http.csrf()
|
http.csrf()
|
||||||
.disable()
|
.disable()
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers("/", "/api/**")
|
.antMatchers("/", "/api/**")
|
||||||
.hasAnyRole(OpenOrgsConstants.VALID_ROLES)
|
.hasAnyRole(OpenOrgsConstants.VALID_ROLES)
|
||||||
.antMatchers("/registration_api/**")
|
.antMatchers("/registration_api/**")
|
||||||
.hasRole(OpenOrgsConstants.NOT_AUTORIZED_ROLE)
|
.hasRole(OpenOrgsConstants.NOT_AUTORIZED_ROLE)
|
||||||
.antMatchers("/common/**", "/resources/**", "/webjars/**", "/metrics", "/health", "/kpis", "/dbmodel/**")
|
.antMatchers("/common/**", "/resources/**", "/webjars/**", "/metrics", "/health", "/kpis", "/dbmodel/**", "/public-api/**")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.antMatchers("/oa_api/**")
|
.antMatchers("/oa_api/**")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated()
|
.authenticated()
|
||||||
.and()
|
.and()
|
||||||
.formLogin()
|
.formLogin()
|
||||||
.loginPage("/login")
|
.loginPage("/login")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.and()
|
.and()
|
||||||
.logout()
|
.logout()
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.and()
|
.and()
|
||||||
.exceptionHandling()
|
.exceptionHandling()
|
||||||
.accessDeniedHandler(accessDeniedHandler());
|
.accessDeniedHandler(accessDeniedHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessDeniedHandler accessDeniedHandler() {
|
private AccessDeniedHandler accessDeniedHandler() {
|
||||||
|
@ -74,7 +74,8 @@ public class MockSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
if (auth != null) {
|
if (auth != null) {
|
||||||
logger
|
logger
|
||||||
.warn(String.format("User '%s' (%s) attempted to access the protected URL: %s", auth.getName(), req.getRemoteAddr(), req.getRequestURI()));
|
.warn(String
|
||||||
|
.format("User '%s' (%s) attempted to access the protected URL: %s", auth.getName(), req.getRemoteAddr(), req.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UserInfo.isNotAuthorized(auth)) {
|
if (UserInfo.isNotAuthorized(auth)) {
|
||||||
|
@ -89,12 +90,12 @@ public class MockSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
@Autowired
|
@Autowired
|
||||||
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
|
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
|
||||||
auth.jdbcAuthentication()
|
auth.jdbcAuthentication()
|
||||||
.dataSource(dataSource)
|
.dataSource(dataSource)
|
||||||
.usersByUsernameQuery("select ?, '{MD5}" + DigestUtils.md5Hex(DEFAULT_PASSWORD) + "', true")
|
.usersByUsernameQuery("select ?, '{MD5}" + DigestUtils.md5Hex(DEFAULT_PASSWORD) + "', true")
|
||||||
.authoritiesByUsernameQuery("with const as (SELECT ? as email) "
|
.authoritiesByUsernameQuery("with const as (SELECT ? as email) "
|
||||||
+ "select c.email, 'ROLE_" + OpenOrgsConstants.OPENORGS_ROLE_PREFIX + "'||coalesce(u.role, '"
|
+ "select c.email, 'ROLE_" + OpenOrgsConstants.OPENORGS_ROLE_PREFIX + "'||coalesce(u.role, '"
|
||||||
+ UserRole.NOT_AUTHORIZED
|
+ UserRole.NOT_AUTHORIZED
|
||||||
+ "') from const c left outer join users u on (u.email = c.email)");
|
+ "') from const c left outer join users u on (u.email = c.email)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -57,29 +57,29 @@ public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
http.headers().frameOptions().sameOrigin();
|
http.headers().frameOptions().sameOrigin();
|
||||||
|
|
||||||
http.csrf()
|
http.csrf()
|
||||||
.disable()
|
.disable()
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers("/main", "/api/**")
|
.antMatchers("/main", "/api/**")
|
||||||
.hasAnyRole(OpenOrgsConstants.VALID_ROLES)
|
.hasAnyRole(OpenOrgsConstants.VALID_ROLES)
|
||||||
.antMatchers("/registration_api/**")
|
.antMatchers("/registration_api/**")
|
||||||
.hasRole(OpenOrgsConstants.NOT_AUTORIZED_ROLE)
|
.hasRole(OpenOrgsConstants.NOT_AUTORIZED_ROLE)
|
||||||
.antMatchers("/", "/common/**", "/resources/**", "/webjars/**", "/metrics", "/health", "/kpis", "/dbmodel/**")
|
.antMatchers("/", "/common/**", "/resources/**", "/webjars/**", "/metrics", "/health", "/kpis", "/dbmodel/**", "/public-api/**")
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.antMatchers("/oa_api/**")
|
.antMatchers("/oa_api/**")
|
||||||
.hasIpAddress(openaireApiValidSubnet)
|
.hasIpAddress(openaireApiValidSubnet)
|
||||||
.anyRequest()
|
.anyRequest()
|
||||||
.authenticated()
|
.authenticated()
|
||||||
.and()
|
.and()
|
||||||
.exceptionHandling()
|
.exceptionHandling()
|
||||||
.accessDeniedHandler(accessDeniedHandler())
|
.accessDeniedHandler(accessDeniedHandler())
|
||||||
.and()
|
.and()
|
||||||
.logout()
|
.logout()
|
||||||
.logoutSuccessHandler(oidcLogoutSuccessHandler())
|
.logoutSuccessHandler(oidcLogoutSuccessHandler())
|
||||||
.invalidateHttpSession(true)
|
.invalidateHttpSession(true)
|
||||||
.clearAuthentication(true)
|
.clearAuthentication(true)
|
||||||
.deleteCookies("JSESSIONID")
|
.deleteCookies("JSESSIONID")
|
||||||
.and()
|
.and()
|
||||||
.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.oidcUserService(this.oidcUserService())));
|
.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.oidcUserService(oidcUserService())));
|
||||||
}
|
}
|
||||||
|
|
||||||
private AccessDeniedHandler accessDeniedHandler() {
|
private AccessDeniedHandler accessDeniedHandler() {
|
||||||
|
@ -87,8 +87,8 @@ public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
if (authentication != null) {
|
if (authentication != null) {
|
||||||
log.warn(String
|
log.warn(String
|
||||||
.format("User '%s' (%s) attempted to access the protected URL: %s", UserInfo.getEmail(authentication), req
|
.format("User '%s' (%s) attempted to access the protected URL: %s", UserInfo.getEmail(authentication), req
|
||||||
.getRemoteAddr(), req.getRequestURI()));
|
.getRemoteAddr(), req.getRequestURI()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UserInfo.isNotAuthorized(authentication)) {
|
if (UserInfo.isNotAuthorized(authentication)) {
|
||||||
|
@ -122,7 +122,7 @@ public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
|
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
|
||||||
final OidcUserService delegate = new OidcUserService();
|
final OidcUserService delegate = new OidcUserService();
|
||||||
|
|
||||||
return (userRequest) -> {
|
return userRequest -> {
|
||||||
final OidcUser oidcUser = delegate.loadUser(userRequest);
|
final OidcUser oidcUser = delegate.loadUser(userRequest);
|
||||||
|
|
||||||
log.debug("User attributes:");
|
log.debug("User attributes:");
|
||||||
|
@ -137,9 +137,9 @@ public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
final String role = "ROLE_" + OpenOrgsConstants.OPENORGS_ROLE_PREFIX + user
|
final String role = "ROLE_" + OpenOrgsConstants.OPENORGS_ROLE_PREFIX + user
|
||||||
.map(User::getRole)
|
.map(User::getRole)
|
||||||
.filter(StringUtils::isNotBlank)
|
.filter(StringUtils::isNotBlank)
|
||||||
.orElse(UserRole.NOT_AUTHORIZED.toString());
|
.orElse(UserRole.NOT_AUTHORIZED.toString());
|
||||||
|
|
||||||
final Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
|
final Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
|
||||||
mappedAuthorities.add(new SimpleGrantedAuthority(role));
|
mappedAuthorities.add(new SimpleGrantedAuthority(role));
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package eu.dnetlib.organizations.controller;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import eu.dnetlib.organizations.model.view.ApiJournalView;
|
||||||
|
import eu.dnetlib.organizations.repository.OrganizationRepository;
|
||||||
|
import eu.dnetlib.organizations.repository.readonly.ApiJournalViewRepository;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/public-api")
|
||||||
|
public class PublicApiController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApiJournalViewRepository apiJournalViewRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrganizationRepository organizationRepository;
|
||||||
|
|
||||||
|
@GetMapping("/logs")
|
||||||
|
public ApiJournalView findJournalByDsId(@RequestParam final String id) {
|
||||||
|
return apiJournalViewRepository.findById(id).orElse(organizationRepository.findById(id).map(ApiJournalView::new).orElse(new ApiJournalView()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/logs/{country}/{page}/{size}")
|
||||||
|
public Page<ApiJournalView> findJournalByCountry(@PathVariable final String country, @PathVariable final int page, @PathVariable final int size) {
|
||||||
|
return apiJournalViewRepository.findByCountry(country, PageRequest.of(page, size));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package eu.dnetlib.organizations.model.utils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
public class ApiOperation implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7111524441502889608L;
|
||||||
|
|
||||||
|
private String operation;
|
||||||
|
private String description;
|
||||||
|
private LocalDateTime date;
|
||||||
|
|
||||||
|
public String getOperation() {
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOperation(final String operation) {
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(final String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDateTime getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDate(final LocalDateTime date) {
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
package eu.dnetlib.organizations.model.view;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Type;
|
||||||
|
import org.hibernate.annotations.TypeDef;
|
||||||
|
import org.hibernate.annotations.TypeDefs;
|
||||||
|
|
||||||
|
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
|
||||||
|
import com.vladmihalcea.hibernate.type.json.JsonStringType;
|
||||||
|
|
||||||
|
import eu.dnetlib.organizations.model.Organization;
|
||||||
|
import eu.dnetlib.organizations.model.utils.ApiOperation;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "api_journal_view")
|
||||||
|
@TypeDefs({
|
||||||
|
@TypeDef(name = "json", typeClass = JsonStringType.class),
|
||||||
|
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
|
||||||
|
})
|
||||||
|
public class ApiJournalView implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1270660185726854334L;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@Column(name = "id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "country")
|
||||||
|
private String country;
|
||||||
|
|
||||||
|
@Type(type = "json")
|
||||||
|
@Column(name = "logs", columnDefinition = "json")
|
||||||
|
private List<ApiOperation> logs;
|
||||||
|
|
||||||
|
public ApiJournalView() {}
|
||||||
|
|
||||||
|
public ApiJournalView(final Organization o) {
|
||||||
|
id = o.getId();
|
||||||
|
name = o.getName();
|
||||||
|
country = o.getCountry();
|
||||||
|
logs = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(final String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCountry() {
|
||||||
|
return country;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCountry(final String country) {
|
||||||
|
this.country = country;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ApiOperation> getLogs() {
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLogs(final List<ApiOperation> logs) {
|
||||||
|
this.logs = logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package eu.dnetlib.organizations.repository.readonly;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import eu.dnetlib.organizations.model.view.ApiJournalView;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface ApiJournalViewRepository extends ReadOnlyRepository<ApiJournalView, String> {
|
||||||
|
|
||||||
|
Page<ApiJournalView> findByCountry(String country, Pageable page);
|
||||||
|
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ DROP VIEW IF EXISTS conflict_groups_view;
|
||||||
DROP VIEW IF EXISTS suggestions_info_by_country_view;
|
DROP VIEW IF EXISTS suggestions_info_by_country_view;
|
||||||
DROP VIEW IF EXISTS duplicate_groups_view;
|
DROP VIEW IF EXISTS duplicate_groups_view;
|
||||||
DROP VIEW IF EXISTS persistent_orgs_view;
|
DROP VIEW IF EXISTS persistent_orgs_view;
|
||||||
|
DROP VIEW IF EXISTS api_journal_view;
|
||||||
|
|
||||||
DROP TABLE IF EXISTS sysconf;
|
DROP TABLE IF EXISTS sysconf;
|
||||||
DROP TABLE IF EXISTS other_ids;
|
DROP TABLE IF EXISTS other_ids;
|
||||||
|
@ -748,3 +749,4 @@ $$;
|
||||||
CREATE TRIGGER insert_or_update_index_search_trigger AFTER INSERT OR UPDATE ON organizations FOR EACH ROW EXECUTE PROCEDURE insert_or_update_index_search_trigger();
|
CREATE TRIGGER insert_or_update_index_search_trigger AFTER INSERT OR UPDATE ON organizations FOR EACH ROW EXECUTE PROCEDURE insert_or_update_index_search_trigger();
|
||||||
CREATE TRIGGER delete_index_search_trigger BEFORE DELETE ON organizations FOR EACH ROW EXECUTE PROCEDURE delete_index_search();
|
CREATE TRIGGER delete_index_search_trigger BEFORE DELETE ON organizations FOR EACH ROW EXECUTE PROCEDURE delete_index_search();
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue