Migrate openaire-users API to spring boot 3 application

This commit is contained in:
Konstantinos Triantafyllou 2024-10-11 16:33:44 +03:00
parent 96b6bd61a4
commit 71338e2825
177 changed files with 15401 additions and 46 deletions

49
.gitignore vendored
View File

@ -1,45 +1,4 @@
# ---> Java
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
# ---> Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
# Eclipse m2e generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
.idea
target
*.iml
make.sh

View File

@ -1,2 +1,51 @@
# uoa-user-management
# Uoa User Management
Uoa User Management is a service which communicates with Role Management and provides method to invite userDetails to be
members or managers of an OpenAIRE entity
## Configuration
Check first [authorization-library](https://code-repo.d4science.org/MaDgIK/authorization-library#stateless).
### Role Management
user-management.developers= # Required - URL of Developers portal (Deprecated)
user-management.loginURL= # Required - URL for Login Action
user-management.role-management= # Required - URL of Role Management API
### Mail
user-management.mail.host # Required - Mail host name
user-management.mail.port # Required - Mail port
user-management.mail.from # Required - From email address
user-management.mail.protocol # Required - Mail protocol
user-management.mail.defaultEncoding # Required - Default Encoding - default value: UTF-8
user-management.mail.sslProtocols # Optional - If ssl Protocols are needed (comma separated)
user-management.mail.auth # Required (boolean) - If authentication is required for mail account - default value: false
user-management.mail.username # Required (if auth = true) - Username of mail account
user-management.mail.password # Required (if auth = true) - Password of mail account
### Google
user-management.google.key # Required - Google site key for Recaptcha
user-management.google.secret # Required - Google secret key for Recaptcha
### Datasource configuration
user-management.datasource.driver # Required - SQL Driver - Default: org.postgresql.Driver
user-management.datasource.url # Required - jdbc URL to the database
user-management.datasource.username # Optional - Database userDetails if needed
user-management.datasource.password # Optional - Database userDetails password if needed
### LDAP Configuration
user-management.ldap.address # Required - LDAP Host address
user-management.ldap.baseDN # Required - LDAP base domain
user-management.ldap.adminDN # Required - LDAP admin domain
user-management.ldap.password # Required - LDAP admin password
user-management.ldap.port # Required - LDAP Host port
## Run
Check [Spring boot Documentation](https://code-repo.d4science.org/MaDgIK/Documentation/wiki/Spring-boot) (need Login)

92
pom.xml Normal file
View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>eu.dnetlib</groupId>
<artifactId>uoa-spring-boot-parent</artifactId>
<version>2.0.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>uoa-user-management</artifactId>
<version>3.0.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>uoa-user-management</name>
<scm>
<developerConnection>scm:git:gitea@code-repo.d4science.org:MaDgIK/uoa-user-management.git</developerConnection>
</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-authorization-library</artifactId>
<version>3.0.3</version>
</dependency>
<!-- PostgresSQL -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- Spring LDAP Core -->
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ldap</artifactId>
</dependency>
<!-- Spring HTML pages -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>eu.dnetlib.uoausermanagment.UserManagementApplication</mainClass>
<executable>true</executable>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
<nonFilteredFileExtension>eot</nonFilteredFileExtension>
<nonFilteredFileExtension>svg</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
<finalName>uoa-user-management</finalName>
</build>
</project>

View File

@ -0,0 +1,2 @@
UPDATE role_verification SET verification_type = 'manager' where verification_type = 'MANAGER';
UPDATE role_verification SET verification_type = 'member' where verification_type = 'MEMBER';

View File

@ -0,0 +1,2 @@
UPDATE role_verification SET verification_type = 'MANAGER' where verification_type = 'manager';
UPDATE role_verification SET verification_type = 'MEMBER' where verification_type = 'member';

View File

@ -0,0 +1,13 @@
package eu.dnetlib.uoausermanagment;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(UserManagementApplication.class);
}
}

View File

@ -0,0 +1,26 @@
package eu.dnetlib.uoausermanagment;
import eu.dnetlib.uoaauthorizationlibrary.SecurityConfiguration;
import eu.dnetlib.uoausermanagment.configuration.GlobalVars;
import eu.dnetlib.uoausermanagment.configuration.Properties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
@SpringBootApplication(scanBasePackages = {"eu.dnetlib.uoausermanagment"})
@PropertySources({
@PropertySource("classpath:authorization.properties"),
@PropertySource("classpath:user-management.properties"),
@PropertySource(value = "classpath:dnet-override.properties", ignoreResourceNotFound = true)
})
@EnableConfigurationProperties({Properties.class, GlobalVars.class})
@Import({SecurityConfiguration.class})
public class UserManagementApplication {
public static void main(String[] args) {
SpringApplication.run(UserManagementApplication.class, args);
}
}

View File

@ -0,0 +1,29 @@
package eu.dnetlib.uoausermanagment.configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
Datasource datasource;
@Autowired
public DataSourceConfig(Properties properties) {
this.datasource = properties.getDatasource();
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(this.datasource.getDriver());
dataSource.setUrl(this.datasource.getUrl());
dataSource.setUsername(this.datasource.getUsername());
dataSource.setPassword(this.datasource.getPassword());
return dataSource;
}
}

View File

@ -0,0 +1,43 @@
package eu.dnetlib.uoausermanagment.configuration;
public class Datasource {
private String driver;
private String url;
private String username;
private String password;
public Datasource() {
}
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}

View File

@ -0,0 +1,38 @@
package eu.dnetlib.uoausermanagment.configuration;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
@Configuration
public class EmailConfig {
private static final Logger logger = LogManager.getLogger(EmailConfig.class);
private final Mail mail;
@Autowired
public EmailConfig(Properties properties) {
this.mail = properties.getMail();
}
@Bean
public JavaMailSender javaMailSender() {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(mail.getHost());
mailSender.setPort(Integer.parseInt(mail.getPort()));
mailSender.setUsername(mail.getUsername());
mailSender.setPassword(mail.getPassword());
mailSender.setProtocol(mail.getProtocol());
mailSender.setDefaultEncoding(mail.getDefaultEncoding());
java.util.Properties properties = mailSender.getJavaMailProperties();
properties.put("mail.smtp.auth", mail.getAuth());
properties.put("mail.smtp.starttls.enable", "true");
if(mail.getSslProtocols() != null) {
properties.put("mail.smtp.ssl.protocols", mail.getSslProtocols());
}
return mailSender;
}
}

View File

@ -0,0 +1,31 @@
package eu.dnetlib.uoausermanagment.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Date;
@ConfigurationProperties("user-management.global-vars")
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

@ -0,0 +1,26 @@
package eu.dnetlib.uoausermanagment.configuration;
public class Google {
private String key;
private String secret;
public Google() {
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
}

View File

@ -0,0 +1,52 @@
package eu.dnetlib.uoausermanagment.configuration;
public class LDAP {
private String address;
private String baseDN;
private String adminDN;
private String password;
private int port = 389;
public LDAP() {
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getBaseDN() {
return baseDN;
}
public void setBaseDN(String baseDN) {
this.baseDN = baseDN;
}
public String getAdminDN() {
return adminDN;
}
public void setAdminDN(String adminDN) {
this.adminDN = adminDN;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}

View File

@ -0,0 +1,31 @@
package eu.dnetlib.uoausermanagment.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;
@Configuration
public class LDAPConfig {
private final LDAP ldap;
public LDAPConfig(Properties properties) {
this.ldap = properties.getLdap();
}
public LdapContextSource ldapContextSource() {
LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl(this.ldap.getAddress() + ":" + this.ldap.getPort());
contextSource.setBase(this.ldap.getBaseDN());
contextSource.setUserDn(this.ldap.getAdminDN());
contextSource.setPassword(this.ldap.getPassword());
contextSource.afterPropertiesSet();
return contextSource;
}
@Bean
public LdapTemplate ldapTemplate() {
return new LdapTemplate(ldapContextSource());
}
}

View File

@ -0,0 +1,89 @@
package eu.dnetlib.uoausermanagment.configuration;
public class Mail {
private String host;
private String port;
private boolean auth = false;
private String defaultEncoding = "UTF-8";
private String from;
private String username;
private String password;
private String protocol;
private String sslProtocols;
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public boolean hasAuth() {
return auth;
}
public String getAuth() {
return String.valueOf(auth);
}
public void setAuth(boolean auth) {
this.auth = auth;
}
public String getDefaultEncoding() {
return defaultEncoding;
}
public void setDefaultEncoding(String defaultEncoding) {
this.defaultEncoding = defaultEncoding;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getProtocol() {
return protocol;
}
public void setProtocol(String protocol) {
this.protocol = protocol;
}
public String getSslProtocols() {
return sslProtocols;
}
public void setSslProtocols(String sslProtocols) {
this.sslProtocols = sslProtocols;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}

View File

@ -0,0 +1,74 @@
package eu.dnetlib.uoausermanagment.configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("user-management")
public class Properties {
/**
* @deprecated
* */
private String developers;
private String roleManagement;
private Mail mail = new Mail();
private Google google = new Google();
private Datasource datasource = new Datasource();
private LDAP ldap = new LDAP();
private String loginUrl;
public String getDevelopers() {
return developers;
}
public void setDevelopers(String developers) {
this.developers = developers;
}
public String getRoleManagement() {
return roleManagement;
}
public void setRoleManagement(String roleManagement) {
this.roleManagement = roleManagement;
}
public Mail getMail() {
return mail;
}
public void setMail(Mail mail) {
this.mail = mail;
}
public Google getGoogle() {
return google;
}
public void setGoogle(Google google) {
this.google = google;
}
public Datasource getDatasource() {
return datasource;
}
public void setDatasource(Datasource datasource) {
this.datasource = datasource;
}
public LDAP getLdap() {
return ldap;
}
public void setLdap(LDAP ldap) {
this.ldap = ldap;
}
public String getLoginUrl() {
return loginUrl;
}
public void setLoginUrl(String loginUrL) {
this.loginUrl = loginUrL;
}
}

View File

@ -0,0 +1,66 @@
package eu.dnetlib.uoausermanagment.controllers;
import eu.dnetlib.uoausermanagment.configuration.Properties;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.io.IOException;
@Controller
public class DeprecatedController {
private final String developers;
@Autowired
public DeprecatedController(Properties properties) {
this.developers = properties.getDevelopers();
}
/**
* Old jsp pages will be redirected to the new pages.
*
* @deprecated
*/
@GetMapping("/{page}.jsp")
public String deprecatedPages(@PathVariable("page") String page) {
switch (page) {
case "requestActivationCode" -> page = "request-code";
case "404" -> page = "error";
case "requestToDeleteAccount" -> page = "request-delete-account";
case "emailConfirmation" -> page = "email-confirmation";
case "remindUsername" -> page = "remind-username";
case "forgotPassword" -> page = "forgot-password";
case "resetPassword" -> page = "reset-password";
case "verifyToDelete" -> page = "delete-account";
}
return "redirect:/" + page;
}
/**
* Old developers pages will be redirected to the new developers' portal.
*
* @deprecated
*/
@GetMapping("/overview")
public void getOverview(HttpServletResponse response) throws IOException {
response.sendRedirect(developers);
}
/**
* @deprecated
*/
@GetMapping({"/registerService", "/registeredServices"})
public void getAPIs(HttpServletResponse response) throws IOException {
response.sendRedirect(developers + "/apis");
}
/**
* @deprecated
*/
@GetMapping("/personalToken")
public void getPersonalToken(HttpServletResponse response) throws IOException {
response.sendRedirect(developers + "/personal-token");
}
}

View File

@ -0,0 +1,253 @@
package eu.dnetlib.uoausermanagment.controllers;
import eu.dnetlib.uoausermanagment.configuration.Google;
import eu.dnetlib.uoausermanagment.configuration.Properties;
import eu.dnetlib.uoausermanagment.dto.form.*;
import eu.dnetlib.uoausermanagment.entities.AccountStatus;
import eu.dnetlib.uoausermanagment.entities.User;
import eu.dnetlib.uoausermanagment.entities.UserVerification;
import eu.dnetlib.uoausermanagment.entities.ZombieUser;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.UserVerificationService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class FormPageController {
private final Google google;
private final ValidationService validationService;
private final UserVerificationService userVerificationService;
private final LDAPService ldapService;
public FormPageController(Properties properties, ValidationService validationService, UserVerificationService userVerificationService, LDAPService ldapService) {
this.google = properties.getGoogle();
this.validationService = validationService;
this.userVerificationService = userVerificationService;
this.ldapService = ldapService;
}
@GetMapping("/register")
public String register(Model model) {
RegisterForm registerForm = new RegisterForm();
model.addAttribute("form", registerForm);
model.addAttribute("siteKey", google.getKey());
return "register";
}
@PostMapping("/register")
public String register(HttpServletRequest request, Model model, RegisterForm form) {
String path = "register";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
ZombieUser zombieUser = this.ldapService.createZombieUser(form, model);
if (!model.containsAttribute("server_error")) {
UserVerification verification = this.userVerificationService.create(zombieUser.getUsername());
this.userVerificationService.sendActivationVerification(request, model, verification, zombieUser.getEmail());
if (!model.containsAttribute("server_error")) {
path = "redirect:/activate";
}
}
}
return this.redirect(model, form, path);
}
@GetMapping("/activate")
public String activateAccount(Model model, @RequestParam(value = "code", required = false) String code) {
model.addAttribute("form", new ActivationForm(code));
model.addAttribute("siteKey", google.getKey());
return "activate";
}
@PostMapping("/activate")
public String activateAccount(HttpServletRequest request, Model model, ActivationForm form) {
String path = "activate";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
path = userVerificationService.validate(request, model, form.getUsername(), form.getVerificationCode(), "activate");
if(path == null) {
String error = this.ldapService.moveUser(form.getUsername());
if(error != null) {
model.addAttribute("server_error", error);
return this.redirect(model, form, "activate");
}
request.getSession().setAttribute("register-success", true);
path = "redirect:/register-success";
}
}
return this.redirect(model, form, path);
}
@GetMapping("/verify")
public String verifyAccount(Model model, @RequestParam(value = "code", required = false) String code) {
model.addAttribute("form", new VerificationForm(code));
model.addAttribute("siteKey", google.getKey());
return "verify";
}
@PostMapping("/verify")
public String verifyAccount(HttpServletRequest request, Model model, VerificationForm form) {
String path = "verify";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
path = userVerificationService.validate(request, model, form.getUsername(), form.getVerificationCode(), "activate");
if(path == null) {
request.getSession().setAttribute("username", form.getUsername());
path = "redirect:/reset-password";
}
}
return this.redirect(model, form, path);
}
@GetMapping("/request-code")
public String requestVerificationCode(Model model) {
model.addAttribute("form", new RequestByUsernameForm());
model.addAttribute("siteKey", google.getKey());
return "request-code";
}
@PostMapping("/request-code")
public String requestVerificationCode(HttpServletRequest request, Model model, RequestByUsernameForm form) {
String path = "request-code";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
ZombieUser user = this.ldapService.getZombieUser(form.getUsername());
UserVerification verification = this.userVerificationService.create(user.getUsername());
this.userVerificationService.sendActivationVerification(request, model, verification, user.getEmail());
if (!model.containsAttribute("server_error")) {
path = "redirect:/activate";
}
}
return this.redirect(model, form, path);
}
@GetMapping("/request-delete-account")
public String requestDeleteAccount(Model model) {
model.addAttribute("form", new RequestByEmailForm());
model.addAttribute("siteKey", google.getKey());
return "request-delete-account";
}
@PostMapping("/request-delete-account")
public String requestDeleteAccount(HttpServletRequest request, Model model, RequestByEmailForm form) {
String path = "request-delete-account";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
String username = ldapService.accountStatusByEmail(form.getEmail()).equals(AccountStatus.ACTIVATED)?
this.ldapService.getUserByEmail(form.getEmail()).getUsername():this.ldapService.getZombieUserByEmail(form.getEmail()).getUsername();
this.userVerificationService.sendVerificationToDelete(request, model, this.userVerificationService.create(username), form.getEmail());
if (!model.containsAttribute("server_error")) {
path = "redirect:/delete-account";
}
}
return this.redirect(model, form, path);
}
@GetMapping("/delete-account")
public String deleteAccount(Model model, @RequestParam(value = "code", required = false) String code) {
model.addAttribute("form", new VerificationForm(code));
model.addAttribute("siteKey", google.getKey());
return "delete-account";
}
@PostMapping("/delete-account")
public String deleteAccount(HttpServletRequest request, Model model, VerificationForm form) {
String path = "delete-account";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
path = userVerificationService.validate(request, model, form.getUsername(), form.getVerificationCode(), "activate");
if(path == null) {
String error = this.ldapService.deleteUser(form.getUsername());
if(error != null) {
model.addAttribute("server_error", error);
return this.redirect(model, form, "delete-account");
}
request.getSession().setAttribute("delete-success", true);
path = "redirect:/delete-success";
}
}
return this.redirect(model, form, path);
}
@GetMapping("/remind-username")
public String remindUsername(Model model) {
model.addAttribute("form", new RequestByEmailForm());
model.addAttribute("siteKey", google.getKey());
return "remind-username";
}
@PostMapping("/remind-username")
public String remindUsername(HttpServletRequest request, Model model, RequestByEmailForm form) {
String path = "remind-username";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
User user = this.ldapService.getUserByEmail(form.getEmail());
if(user == null) {
model.addAttribute("server_error", "Your account is not activated.");
} else {
this.userVerificationService.sendUsernameReminder(model, this.userVerificationService.create(user.getUsername()), form.getEmail());
if (!model.containsAttribute("server_error")) {
request.getSession().setAttribute("email-success", true);
path = "redirect:/email-success";
}
}
}
return this.redirect(model, form, path);
}
@GetMapping("/forgot-password")
public String forgotPassword(Model model) {
model.addAttribute("form", new RequestByEmailForm());
model.addAttribute("siteKey", google.getKey());
return "forgot-password";
}
@PostMapping("/forgot-password")
public String forgotPassword(HttpServletRequest request, Model model, RequestByEmailForm form) {
String path = "forgot-password";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
User user = this.ldapService.getUserByEmail(form.getEmail());
if(user == null) {
model.addAttribute("server_error", "Your account is not activated.");
} else {
this.userVerificationService.sendForgotPasswordVerification(request, model, this.userVerificationService.create(user.getUsername()), form.getEmail());
if (!model.containsAttribute("server_error")) {
path = "verify";
}
}
}
return this.redirect(model, form, path);
}
@GetMapping("/reset-password")
public String resetPassword(HttpServletRequest request, Model model) {
String username = (String) request.getSession().getAttribute("username");
if (username != null) {
request.getSession().removeAttribute("username");
model.addAttribute("form", new ResetPasswordForm(username));
model.addAttribute("siteKey", google.getKey());
return "reset-password";
}
return "redirect:/error";
}
@PostMapping("/reset-password")
public String resetPassword(HttpServletRequest request, Model model, ResetPasswordForm form) {
String path = "reset-password";
if (form.validate(ldapService, validationService, model, request.getParameter("g-recaptcha-response"))) {
String error = this.ldapService.updateUserPassword(form.getUsername(), form.getPassword());
if(error != null) {
model.addAttribute("server_error", error);
} else {
request.getSession().setAttribute("password-success", true);
path = "redirect:/password-success";
}
}
return this.redirect(model, form, path);
}
private String redirect(Model model, Form form, String path) {
form.clearPassword();
model.addAttribute("form", form);
model.addAttribute("siteKey", google.getKey());
return path;
}
}

View File

@ -0,0 +1,39 @@
package eu.dnetlib.uoausermanagment.controllers;
import eu.dnetlib.uoausermanagment.services.DeployService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/")
public class HealthCheckDeployController {
private final Logger log = LogManager.getLogger(this.getClass());
private final DeployService service;
@Autowired
public HealthCheckDeployController(DeployService service) {
this.service = service;
}
@RequestMapping(value = {"","/", "/health_check"}, method = RequestMethod.GET)
public ResponseEntity<String> hello() {
log.debug("Hello from uoa-user-management!");
return ResponseEntity.ok("Hello from uoa-user-management!");
}
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN)")
@RequestMapping(value = "/health_check/advanced", method = RequestMethod.GET)
public ResponseEntity<Map<String, String>> checkEverything() {
return ResponseEntity.ok(this.service.getProperties());
}
}

View File

@ -0,0 +1,85 @@
package eu.dnetlib.uoausermanagment.controllers;
import eu.dnetlib.uoausermanagment.configuration.Properties;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Objects;
@Controller
public class PageController {
private final String loginUrl;
@Autowired
public PageController(Properties properties) {
this.loginUrl = properties.getLoginUrl();
}
/**
* General Error page
*/
@GetMapping("/bad-request")
public String error(HttpServletRequest request) {
if (request.getSession().getAttribute("error") != null) {
request.getSession().removeAttribute("error");
return "general-error";
}
return "redirect:/error";
}
@GetMapping("/expired")
public String expired(HttpServletRequest request) {
if (Objects.equals(request.getSession().getAttribute("expired"), true)) {
request.getSession().removeAttribute("expired");
return "expired";
}
return "redirect:/error";
}
@GetMapping("/register-success")
public String registerSuccess(HttpServletRequest request, Model model) {
if (Objects.equals(request.getSession().getAttribute("register-success"), true)) {
request.getSession().removeAttribute("register-success");
model.addAttribute("loginUrl", loginUrl);
return "register-success";
}
return "redirect:/error";
}
@GetMapping("/email-success")
public String emailSuccess(HttpServletRequest request) {
if (Objects.equals(request.getSession().getAttribute("email-success"), true)) {
request.getSession().removeAttribute("email-success");
return "email-success";
}
return "redirect:/error";
}
@GetMapping("/password-success")
public String passwordSuccess(HttpServletRequest request) {
if (Objects.equals(request.getSession().getAttribute("password-success"), true)) {
request.getSession().removeAttribute("password-success");
return "password-success";
}
return "redirect:/error";
}
@GetMapping("/delete-success")
public String deleteSuccess(HttpServletRequest request) {
if (Objects.equals(request.getSession().getAttribute("delete-success"), true)) {
request.getSession().removeAttribute("delete-success");
return "delete-success";
}
return "redirect:/error";
}
@GetMapping("/email-confirmation")
public String confirmEmail() {
return "email-confirmation";
}
}

View File

@ -0,0 +1,244 @@
package eu.dnetlib.uoausermanagment.controllers;
import eu.dnetlib.uoaauthorizationlibrary.authorization.exceptions.http.ConflictException;
import eu.dnetlib.uoaauthorizationlibrary.authorization.security.AuthorizationService;
import eu.dnetlib.uoausermanagment.dto.*;
import eu.dnetlib.uoausermanagment.entities.RoleVerification;
import eu.dnetlib.uoausermanagment.services.RoleManagementService;
import eu.dnetlib.uoausermanagment.services.RoleVerificationService;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/registry")
public class RegistryController {
private final RoleManagementService roleManagementService;
private final AuthorizationService authorizationService;
private final RoleVerificationService roleVerificationService;
@Autowired
public RegistryController(RoleManagementService roleManagementService, AuthorizationService authorizationService, RoleVerificationService roleVerificationService) {
this.roleManagementService = roleManagementService;
this.authorizationService = authorizationService;
this.roleVerificationService = roleVerificationService;
}
/**
* Subscribe to a type(Community, etc.) with id(ee, egi, etc.)
*/
@RequestMapping(value = "/subscribe/{type}/{id}", method = RequestMethod.POST)
@PreAuthorize("isAuthenticated() and #type.equals('community')")
public ResponseEntity<StringResult> subscribe(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(roleManagementService.assignMemberRole(type, id, request));
}
/**
* Unsubscribe from type(Community, etc.) with id(ee, egi, etc.).
* If user has manager role for this entity, it will be removed too.
*/
@RequestMapping(value = "/unsubscribe/{type}/{id}", method = RequestMethod.POST)
@PreAuthorize("isAuthenticated() and #type.equals('community')")
public ResponseEntity<StringResult> unsubscribe(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(roleManagementService.removeMemberRole(type, id, request));
}
/**
* Create a new curator role with the given type(Community, etc.).
**/
@RequestMapping(value = "/create/{type}", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN)")
public ResponseEntity<StringResult> createCuratorRole(HttpServletRequest request, @PathVariable("type") String type) {
return ResponseEntity.ok(roleManagementService.createCuratorRole(type, request));
}
/**
* Create a new role with the given type(Community, etc.) with id(ee, egi, etc.).
**/
@RequestMapping(value = "/create/{type}/{id}", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, @AuthorizationService.curator(#type))")
public ResponseEntity<List<StringResult>> createMemberRole(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(roleManagementService.createMemberRole(type, id, request));
}
/**
* Invite user with email to manage a type(Community, etc.) with id(ee, egi, etc.)
* Auto generated link and code will be sent as response.
*/
@RequestMapping(value = "/invite/{type}/{id}/manager", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, @AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
public ResponseEntity<Invitation> inviteManager(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id,
@RequestBody EmailDetails details) {
if(!roleManagementService.isManager(type, id, details.getEmail().getRecipient(), request)) {
return ResponseEntity.ok(roleVerificationService.inviteManager(details, type, id));
}
throw new ConflictException("User has been already manager of this " + type);
}
/**
* Invite user with email to be a member of a type(Community, etc.) with id(ee, egi, etc.)
* Auto generated link and code will be sent as response.
*/
@RequestMapping(value = "/invite/{type}/{id}/member", method = RequestMethod.POST)
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, @AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
public ResponseEntity<Invitation> inviteMember(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id,
@RequestBody EmailDetails details) {
if(!roleManagementService.isMember(type, id, details.getEmail().getRecipient(), request)) {
return ResponseEntity.ok(roleVerificationService.inviteMember(details, type, id));
}
throw new ConflictException("User has been already member of this " + type);
}
/**
* Cancel invitation to user with email for managing a type(Community, etc.) with id(ee, egi, etc.)
*/
@RequestMapping(value = "/invite/{type}/{id}/manager/{email}", method = RequestMethod.DELETE)
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, @AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
public ResponseEntity<StringResult> cancelManagerInvitations(@PathVariable("type") String type, @PathVariable("id") String id, @PathVariable("email") String email) {
this.roleVerificationService.cancelManagerInvitation(type, id, email);
return ResponseEntity.ok(new StringResult(this.authorizationService.manager(type, id), "Invitations have been deleted"));
}
/**
* Cancel invitation to user with email for being member of a type(Community, etc.) with id(ee, egi, etc.)
*/
@RequestMapping(value = "/invite/{type}/{id}/member/{email}", method = RequestMethod.DELETE)
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, @AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
public ResponseEntity<StringResult> cancelMemberInvitations(@PathVariable("type") String type, @PathVariable("id") String id, @PathVariable("email") String email) {
this.roleVerificationService.cancelMemberInvitation(type, id, email);
return ResponseEntity.ok(new StringResult(this.authorizationService.member(type, id), "Invitations have been deleted"));
}
/**
* Get the invited managers for a type(Community, etc.) with id(ee, egi, etc.)
*/
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, " +
"@AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
@RequestMapping(value = "/invite/{type}/{id}/managers", method = RequestMethod.GET)
public ResponseEntity<List<String>> getInvitedManagers(@PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(roleVerificationService.getInvitedManagers(type, id));
}
/**
* Get the invited members for a type(Community, etc.) with id(ee, egi, etc.)
*/
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, " +
"@AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
@RequestMapping(value = "/invite/{type}/{id}/members", method = RequestMethod.GET)
public ResponseEntity<List<String>> getInviteMembers(@PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(roleVerificationService.getInvitedMembers(type, id));
}
/**
* Get the verification with a specific id only if it refers to the logged-in user
*/
@PreAuthorize("@Verification.isMyVerification(#id)")
@RequestMapping(value = "/verification/{id}", method = RequestMethod.GET)
public ResponseEntity<RoleVerification> getVerification(@PathVariable("id") String id) {
return ResponseEntity.ok(roleVerificationService.getRoleVerification(id));
}
/**
* Delete the verification with a specific id.
*/
@PreAuthorize("@Verification.isMyVerification(#id)")
@RequestMapping(value = "/verification/{id}", method = RequestMethod.DELETE)
public ResponseEntity<StringResult> deleteVerification(@PathVariable("id") String id) {
String role = this.roleVerificationService.getRoleFromVerification(id);
this.roleVerificationService.deleteVerification(id);
return ResponseEntity.ok(new StringResult(role, "Verification deleted"));
}
/**
* Verify the verification with the specific id, if the code is correct, and it refers to the logged-in user.
* Manager role is assigned to this user, along with the member role.
*/
@PreAuthorize("@Verification.isMyManagerVerification(#id)")
@RequestMapping(value = "/verification/manager/{id}", method = RequestMethod.POST)
public ResponseEntity<StringResult> verifyManager(HttpServletRequest request, @PathVariable("id") String id, @RequestBody String code) {
RoleVerification verification = this.roleVerificationService.getRoleVerification(id);
this.roleVerificationService.verify(id, code);
this.roleManagementService.assignManagerRole(verification.getType(), verification.getEntity(), request);
if(roleVerificationService.isCommunity(verification.getType())) {
this.roleManagementService.assignMemberRole("ri", verification.getEntity(), request);
}
this.roleVerificationService.cancelAllInvitation(verification.getType(), verification.getEntity(), verification.getEmail());
return ResponseEntity.ok(new StringResult(this.authorizationService.manager(verification.getType(), verification.getEntity()), "Role has been assigned"));
}
/**
* Verify the verification with the specific id, if the code is correct, and it refers to the logged-in user.
* Member role is assigned to this user, along with the member role.
*/
@PreAuthorize("@Verification.isMyMemberVerification(#id)")
@RequestMapping(value = "/verification/member/{id}", method = RequestMethod.POST)
public ResponseEntity<StringResult> verifyMember(HttpServletRequest request, @PathVariable("id") String id, @RequestBody String code) {
RoleVerification verification = this.roleVerificationService.getRoleVerification(id);
this.roleVerificationService.verify(id, code);
this.roleManagementService.assignMemberRole(verification.getType(), verification.getEntity(), request);
this.roleVerificationService.cancelMemberInvitation(verification.getType(), verification.getEntity(), verification.getEmail());
return ResponseEntity.ok(new StringResult(this.authorizationService.member(verification.getType(), verification.getEntity()), "Role has been assigned"));
}
/**
* Remove the manager role from user with email for a type(Community, etc.) with id(ee, egi, etc.)
*/
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, " +
"@AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
@RequestMapping(value = "/{type}/{id}/manager/{email}", method = RequestMethod.DELETE)
public ResponseEntity<StringResult> removeManagerRole(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id, @PathVariable("email") String email) {
return ResponseEntity.ok(roleManagementService.removeManagerRole(type, id, email, request));
}
/**
* Remove the member role from user with email for a type(Community, etc.) with id(ee, egi, etc.)
*/
@PreAuthorize("hasAnyAuthority(@AuthorizationService.PORTAL_ADMIN, " +
"@AuthorizationService.curator(#type), @AuthorizationService.manager(#type, #id))")
@RequestMapping(value = "/{type}/{id}/member/{email}", method = RequestMethod.DELETE)
public ResponseEntity<StringResult> removeMemberRole(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id, @PathVariable String email) {
return ResponseEntity.ok(roleManagementService.removeMemberRole(type, id, email, request));
}
/**
* Get the number of the members of a type(Community, etc.) with id(ee, egi, etc.)
*/
@RequestMapping(value = "/{type}/{id}/members/count", method = RequestMethod.GET)
public ResponseEntity<Result<Integer>> getMembersCount(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(new Result<>(authorizationService.member(type, id), roleManagementService.getAllMembersCount(type, id, request)));
}
/**
* Get infos of the curators of a type(Community, etc.)
*/
@RequestMapping(value = "/{type}/{id}/members", method = RequestMethod.GET)
public ResponseEntity<Result<?>> getMembers(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(new Result<>(authorizationService.member(type, id), roleManagementService.getAllMembers(type, id, request)));
}
/**
* Get infos of the curators of a type(Community, etc.)
*/
@RequestMapping(value = "/{type}/{id}/managers", method = RequestMethod.GET)
public ResponseEntity<Result<UserDetails[]>> getManagers(HttpServletRequest request, @PathVariable("type") String type, @PathVariable("id") String id) {
return ResponseEntity.ok(new Result<>(authorizationService.manager(type, id), roleManagementService.getAllManagers(type, id, request)));
}
/**
* Get infos of the curators of a type(Community, etc.)
*/
@RequestMapping(value = "/{type}/curators", method = RequestMethod.GET)
public ResponseEntity<Result<UserDetails[]>> getCurators(HttpServletRequest request, @PathVariable("type") String type) {
return ResponseEntity.ok(new Result<>(authorizationService.curator(type), roleManagementService.getAllCurators(type, request)));
}
}

View File

@ -0,0 +1,20 @@
package eu.dnetlib.uoausermanagment.dao;
import eu.dnetlib.uoausermanagment.entities.RoleVerification;
import eu.dnetlib.uoausermanagment.entities.VerificationType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Repository
public interface RoleVerificationDAO extends JpaRepository<RoleVerification, String> {
Optional<RoleVerification> findByVerificationTypeAndTypeAndEntityAndEmail(VerificationType verificationType, String type, String entity, String email);
@Transactional
void deleteByVerificationTypeAndTypeAndEntityAndEmail(VerificationType verificationType, String type, String entity, String email);
List<RoleVerification> findByVerificationTypeAndTypeAndEntity(VerificationType verificationType, String type, String entity);
Optional<RoleVerification> findByIdAndVerificationType(String id, VerificationType verificationType);
Optional<RoleVerification> findByIdAndVerificationCode(String id, String verificationCode);
}

View File

@ -0,0 +1,13 @@
package eu.dnetlib.uoausermanagment.dao;
import eu.dnetlib.uoausermanagment.entities.User;
import org.springframework.data.ldap.repository.LdapRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends LdapRepository<User> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}

View File

@ -0,0 +1,14 @@
package eu.dnetlib.uoausermanagment.dao;
import eu.dnetlib.uoausermanagment.entities.UserVerification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserVerificationDAO extends JpaRepository<UserVerification, Long> {
Optional<UserVerification> findByUsername(String username);
Optional<UserVerification> findByUsernameAndVerificationCode(String username, String verificationCode);
}

View File

@ -0,0 +1,15 @@
package eu.dnetlib.uoausermanagment.dao;
import eu.dnetlib.uoausermanagment.entities.User;
import eu.dnetlib.uoausermanagment.entities.ZombieUser;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import javax.naming.Name;
import java.util.Optional;
@Repository
public interface ZombieUserRepository extends CrudRepository<ZombieUser, Name> {
Optional<ZombieUser> findByUsername(String username);
Optional<ZombieUser> findByEmail(String email);
}

View File

@ -0,0 +1,40 @@
package eu.dnetlib.uoausermanagment.dto;
public class Email {
private String body;
private String subject;
private String recipient;
public Email() {
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public void replaceBody(String link, Invitation invitation) {
this.body = this.body.replace("((__user__))", "User").
replace("((__link__))", link + invitation.getLink()).
replace("((__code__))", invitation.getCode());
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getRecipient() {
return recipient;
}
public void setRecipient(String recipient) {
this.recipient = recipient;
}
}

View File

@ -0,0 +1,25 @@
package eu.dnetlib.uoausermanagment.dto;
public class EmailDetails {
private String link;
private Email email;
public EmailDetails() {
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public Email getEmail() {
return email;
}
public void setEmail(Email email) {
this.email = email;
}
}

View File

@ -0,0 +1,96 @@
package eu.dnetlib.uoausermanagment.dto;
import com.fasterxml.jackson.annotation.*;
import java.util.HashMap;
import java.util.Map;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonPropertyOrder({
"success",
"challenge_ts",
"hostname",
"error-codes"
})
public class GoogleResponse {
@JsonProperty("success")
private boolean success;
@JsonProperty("challenge_ts")
private String challengeTs;
@JsonProperty("hostname")
private String hostname;
@JsonProperty("error-codes")
private ErrorCode[] errorCodes;
@JsonIgnore
public boolean hasClientError() {
ErrorCode[] errors = getErrorCodes();
if(errors == null) {
return false;
}
for(ErrorCode error : errors) {
switch(error) {
case InvalidResponse:
case MissingResponse:
return true;
}
}
return false;
}
static enum ErrorCode {
MissingSecret, InvalidSecret,
MissingResponse, InvalidResponse;
private static Map<String, ErrorCode> errorsMap = new HashMap<>(4);
static {
errorsMap.put("missing-input-secret", MissingSecret);
errorsMap.put("invalid-input-secret", InvalidSecret);
errorsMap.put("missing-input-response", MissingResponse);
errorsMap.put("invalid-input-response", InvalidResponse);
}
@JsonCreator
public static ErrorCode forValue(String value) {
return errorsMap.get(value.toLowerCase());
}
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getChallengeTs() {
return challengeTs;
}
public void setChallengeTs(String challengeTs) {
this.challengeTs = challengeTs;
}
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
public ErrorCode[] getErrorCodes() {
return errorCodes;
}
public void setErrorCodes(ErrorCode[] errorCodes) {
this.errorCodes = errorCodes;
}
}

View File

@ -0,0 +1,32 @@
package eu.dnetlib.uoausermanagment.dto;
import eu.dnetlib.uoausermanagment.entities.RoleVerification;
public class Invitation {
private String link;
private String code;
public Invitation() {
}
public Invitation(RoleVerification roleVerification) {
this.link = roleVerification.getId();
this.code = roleVerification.getVerificationCode();
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}

View File

@ -0,0 +1,30 @@
package eu.dnetlib.uoausermanagment.dto;
public class Result<T> {
private String role;
private T response;
public Result() {
}
public Result(String role, T response) {
this.role = role;
this.response = response;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public T getResponse() {
return response;
}
public void setResponse(T response) {
this.response = response;
}
}

View File

@ -0,0 +1,12 @@
package eu.dnetlib.uoausermanagment.dto;
public class StringResult extends Result<String> {
public StringResult() {
super();
}
public StringResult(String role, String response) {
super(role, response);
}
}

View File

@ -0,0 +1,52 @@
package eu.dnetlib.uoausermanagment.dto;
public class UserDetails {
private String id;
private String email;
private String name;
private Boolean isManager;
private String memberSince;
public UserDetails() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boolean isIsManager() {
return isManager;
}
public void setIsManager(Boolean isManager) {
this.isManager = isManager;
}
public String getMemberSince() {
return memberSince;
}
public void setMemberSince(String memberSince) {
this.memberSince = memberSince;
}
}

View File

@ -0,0 +1,19 @@
package eu.dnetlib.uoausermanagment.dto.form;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import org.springframework.ui.Model;
public class ActivationForm extends RequestByUsernameForm {
public ActivationForm(String verificationCode) {
this.verificationCode = verificationCode;
}
@Override
public boolean validate(LDAPService ldapService, ValidationService validationService, Model model, String recaptchaResponse) {
String verificationCodeError = validationService.validateRequired(verificationCode, "Please enter your activation code");
model.addAttribute("verification_code_error", verificationCodeError);
return verificationCodeError == null && super.validate(ldapService, validationService, model, recaptchaResponse);
}
}

View File

@ -0,0 +1,100 @@
package eu.dnetlib.uoausermanagment.dto.form;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import org.springframework.ui.Model;
import java.io.Serializable;
public abstract class Form implements Serializable {
protected String username;
protected String password;
protected String passwordConfirmation;
protected String firstName;
protected String lastName;
protected String organization;
protected String email;
protected String emailConfirmation;
protected String verificationCode;
public boolean validate(LDAPService ldapService, ValidationService validationService, Model model, String recaptchaResponse) {
return false;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordConfirmation() {
return passwordConfirmation;
}
public void setPasswordConfirmation(String passwordConfirmation) {
this.passwordConfirmation = passwordConfirmation;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getOrganization() {
return organization;
}
public void setOrganization(String organization) {
this.organization = organization;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getEmailConfirmation() {
return emailConfirmation;
}
public void setEmailConfirmation(String emailConfirmation) {
this.emailConfirmation = emailConfirmation;
}
public String getVerificationCode() {
return verificationCode;
}
public void setVerificationCode(String verificationCode) {
this.verificationCode = verificationCode;
}
public void clearPassword() {
password = null;
passwordConfirmation = null;
}
}

View File

@ -0,0 +1,37 @@
package eu.dnetlib.uoausermanagment.dto.form;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import org.springframework.ui.Model;
import java.io.Serializable;
public class RegisterForm extends Form implements Serializable {
public RegisterForm() {
}
@Override
public boolean validate(LDAPService ldapService, ValidationService validationService, Model model, String recaptchaResponse) {
String usernameError = validationService.validateUsername(username);
if(usernameError == null && ldapService.usernameExists(username)) {
usernameError = "Username " + username + " already exists";
}
model.addAttribute("username_error", usernameError);
String passwordError = validationService.validatePassword(password, passwordConfirmation);
model.addAttribute("password_error", passwordError);
String emailError = validationService.validateEmail(email, emailConfirmation);
if(emailError == null && ldapService.emailExists(email)) {
emailError = "Email " + email + " already exists";
}
model.addAttribute("email_error", emailError);
String firstNameError = validationService.validateRequired(firstName, "Please enter your first name");
model.addAttribute("first_name_error", firstNameError);
String lastNameError = validationService.validateRequired(lastName, "Please enter your last name");
model.addAttribute("last_name_error", lastNameError);
String recaptchaError = validationService.validateRecaptcha(recaptchaResponse);
model.addAttribute("recaptcha_error", recaptchaError);
return usernameError == null && passwordError == null && emailError == null &&
firstNameError == null && lastNameError == null && recaptchaError == null;
}
}

View File

@ -0,0 +1,25 @@
package eu.dnetlib.uoausermanagment.dto.form;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import org.springframework.ui.Model;
public class RequestByEmailForm extends Form {
public RequestByEmailForm() {
}
@Override
public boolean validate(LDAPService ldapService, ValidationService validationService, Model model, String recaptchaResponse) {
String emailError = validationService.validateEmail(email);
if(emailError == null) {
if(!ldapService.emailExists(email)) {
emailError = "Email " + email + " does not exist";
}
}
model.addAttribute("email_error", emailError);
String recaptchaError = validationService.validateRecaptcha(recaptchaResponse);
model.addAttribute("recaptcha_error", recaptchaError);
return emailError == null && recaptchaError == null;
}
}

View File

@ -0,0 +1,31 @@
package eu.dnetlib.uoausermanagment.dto.form;
import eu.dnetlib.uoausermanagment.entities.AccountStatus;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import org.springframework.ui.Model;
public class RequestByUsernameForm extends Form {
protected boolean shouldActivate = false;
public RequestByUsernameForm() {
}
@Override
public boolean validate(LDAPService ldapService, ValidationService validationService, Model model, String recaptchaResponse) {
String usernameError = validationService.validateRequired(username, "Please enter your username");
if(usernameError == null) {
if(!ldapService.usernameExists(username)) {
usernameError = "Username " + username + " does not exist";
} else if(!shouldActivate && ldapService.accountStatus(username).equals(AccountStatus.ACTIVATED)) {
usernameError = "User with username " + username + " is already activated";
} else if(shouldActivate && !ldapService.accountStatus(username).equals(AccountStatus.ACTIVATED)) {
usernameError = "User with username " + username + " is not activated";
}
}
model.addAttribute("username_error", usernameError);
String recaptchaError = validationService.validateRecaptcha(recaptchaResponse);
model.addAttribute("recaptcha_error", recaptchaError);
return usernameError == null && recaptchaError == null;
}
}

View File

@ -0,0 +1,20 @@
package eu.dnetlib.uoausermanagment.dto.form;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import org.springframework.ui.Model;
public class ResetPasswordForm extends RequestByUsernameForm {
public ResetPasswordForm(String username) {
this.username = username;
}
@Override
public boolean validate(LDAPService ldapService, ValidationService validationService, Model model, String recaptchaResponse) {
String passwordError = validationService.validatePassword(password, passwordConfirmation);
model.addAttribute("password_error", passwordError);
shouldActivate = true;
return passwordError == null && super.validate(ldapService, validationService, model, recaptchaResponse);
}
}

View File

@ -0,0 +1,20 @@
package eu.dnetlib.uoausermanagment.dto.form;
import eu.dnetlib.uoausermanagment.services.LDAPService;
import eu.dnetlib.uoausermanagment.services.ValidationService;
import org.springframework.ui.Model;
public class VerificationForm extends RequestByUsernameForm {
public VerificationForm(String verificationCode) {
this.verificationCode = verificationCode;
}
@Override
public boolean validate(LDAPService ldapService, ValidationService validationService, Model model, String recaptchaResponse) {
shouldActivate = true;
String verificationCodeError = validationService.validateRequired(verificationCode, "Please enter your verification code");
model.addAttribute("verification_code_error", verificationCodeError);
return verificationCodeError == null && super.validate(ldapService, validationService, model, recaptchaResponse);
}
}

View File

@ -0,0 +1,5 @@
package eu.dnetlib.uoausermanagment.entities;
public enum AccountStatus {
NOT_FOUND, ZOMBIE, ACTIVATED
}

View File

@ -0,0 +1,113 @@
package eu.dnetlib.uoausermanagment.entities;
import com.fasterxml.jackson.annotation.JsonProperty;
import eu.dnetlib.uoausermanagment.dao.RoleVerificationDAO;
import jakarta.persistence.*;
import java.util.Date;
import java.util.Random;
@Entity
public class RoleVerification {
private final static Random random = new Random();
@Id
private String id;
private String email;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String verificationCode;
@Enumerated(EnumType.STRING)
private VerificationType verificationType;
private String type;
private String entity;
@Temporal(TemporalType.TIMESTAMP)
private Date date;
public RoleVerification() {
}
public RoleVerification(RoleVerificationDAO dao, String email, VerificationType verificationType, String type, String entity) {
do {
this.id = this.createId();
} while (dao.existsById(this.id));
this.email = email;
this.verificationCode = this.createVerificationCode();
this.verificationType = verificationType;
this.type = type;
this.entity = entity;
this.date = new Date();
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getVerificationCode() {
return this.verificationCode;
}
public void setVerificationCode(String verificationCode) {
this.verificationCode = verificationCode;
}
public VerificationType getVerificationType() {
return this.verificationType;
}
public void setVerificationType(VerificationType verificationType) {
this.verificationType = verificationType;
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
public String getEntity() {
return this.entity;
}
public void setEntity(String entity) {
this.entity = entity;
}
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
private String createId() {
return random.ints(48, 123)
.filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
.limit(16)
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
}
private String createVerificationCode() {
StringBuilder code = new StringBuilder();
for (int i = 0; i < 6; i++) {
code.append(random.nextInt(9));
}
return code.toString();
}
}

View File

@ -0,0 +1,172 @@
package eu.dnetlib.uoausermanagment.entities;
import org.springframework.data.domain.Persistable;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import org.springframework.ldap.odm.annotations.Transient;
import org.springframework.ldap.support.LdapUtils;
import javax.naming.Name;
import java.util.List;
@Entry(base = "ou=users", objectClasses = {"inetOrgPerson", "eduPerson"})
public class User implements Persistable<Name> {
@Id
private Name dn;
@Attribute(name = "uid")
private String username;
@Attribute(name = "cn")
private String commonName;
@Attribute(name = "sn")
private String surname;
@Attribute(name = "givenName")
private String givenName;
@Attribute(name = "mail")
private String email;
@Attribute(name = "eduPersonPrincipalName")
private String eduPersonPrincipalName;
@Attribute(name = "displayName")
private String displayName;
@Attribute(name = "o")
private String organization;
@Attribute(name = "userPassword")
private String userPassword;
@Attribute(name = "objectClass")
private List<String> objectClass;
@Transient
private boolean isNew;
public User() {
}
public User(ZombieUser user) {
this.dn = LdapUtils.newLdapName("uid=" + user.getUsername() + ",ou=users");
this.username = user.getUsername();
this.commonName = this.username;
this.givenName = user.getGivenName();
this.surname = user.getSurname();
this.displayName = user.getDisplayName();
this.organization = user.getOrganization();
this.email = user.getEmail();
this.eduPersonPrincipalName = user.getEduPersonPrincipalName();
this.userPassword = user.getStoredPassword();
this.objectClass = user.getObjectClass();
this.isNew = true;
}
public Name getDn() {
return dn;
}
public void setDn(Name dn) {
this.dn = dn;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCommonName() {
return commonName;
}
public void setCommonName(String commonName) {
this.commonName = commonName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getGivenName() {
return givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getEduPersonPrincipalName() {
return eduPersonPrincipalName;
}
public void setEduPersonPrincipalName(String eduPersonPrincipalName) {
this.eduPersonPrincipalName = eduPersonPrincipalName;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getOrganization() {
return organization;
}
public void setOrganization(String organization) {
this.organization = organization;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public List<String> getObjectClass() {
return objectClass;
}
public void setObjectClass(List<String> objectClass) {
this.objectClass = objectClass;
}
@Override
public Name getId() {
return this.getDn();
}
@Override
public boolean isNew() {
return this.isNew;
}
public void setNew(boolean isNew) {
this.isNew = isNew;
}
}

View File

@ -0,0 +1,69 @@
package eu.dnetlib.uoausermanagment.entities;
import jakarta.persistence.*;
import java.util.Date;
import java.util.UUID;
@Entity
public class UserVerification {
private static final long EXPIRE_AFTER = 24 * 60 * 60 * 1000;
@Id()
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String verificationCode;
@Temporal(TemporalType.TIMESTAMP)
private Date date;
public UserVerification() {}
public UserVerification(String username) {
this.username = username;
}
public void updateVerificationCode() {
this.verificationCode = UUID.randomUUID().toString();
this.date = new Date();
}
public Long getId(){
return id;
}
public void setId(Long id){
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getVerificationCode() {
return verificationCode;
}
public void setVerificationCode(String verificationCode) {
this.verificationCode = verificationCode;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public boolean expired() {
return new Date().getTime() - date.getTime() > EXPIRE_AFTER;
}
}

View File

@ -0,0 +1,5 @@
package eu.dnetlib.uoausermanagment.entities;
public enum VerificationType {
MEMBER, MANAGER
}

View File

@ -0,0 +1,185 @@
package eu.dnetlib.uoausermanagment.entities;
import eu.dnetlib.uoausermanagment.dto.form.RegisterForm;
import org.springframework.data.domain.Persistable;
import org.springframework.ldap.odm.annotations.Attribute;
import org.springframework.ldap.odm.annotations.Entry;
import org.springframework.ldap.odm.annotations.Id;
import org.springframework.ldap.odm.annotations.Transient;
import org.springframework.ldap.support.LdapUtils;
import javax.naming.Name;
import java.util.Arrays;
import java.util.List;
@Entry(base = "ou=zombies", objectClasses = {"inetOrgPerson", "eduPerson"})
public final class ZombieUser implements Persistable<Name> {
@Id
private Name dn;
@Attribute(name = "uid")
private String username;
@Attribute(name = "cn")
private String commonName;
@Attribute(name = "sn")
private String surname;
@Attribute(name = "givenName")
private String givenName;
@Attribute(name = "mail")
private String email;
@Attribute(name = "eduPersonPrincipalName")
private String eduPersonPrincipalName;
@Attribute(name = "displayName")
private String displayName;
@Attribute(name = "o")
private String organization;
@Attribute(name = "userPassword")
private String userPassword;
@Attribute(name = "objectClass")
private List<String> objectClass;
@Transient
private boolean isNew;
public ZombieUser() {
}
public ZombieUser(RegisterForm form) {
this.dn = LdapUtils.newLdapName("uid=" + form.getUsername() + ",ou=zombies");
this.username = form.getUsername();
this.commonName = this.username;
this.givenName = form.getFirstName();
this.surname = form.getLastName();
this.displayName = this.givenName + " " + this.surname;
this.organization = !form.getOrganization().isEmpty() ? form.getOrganization() : null;
this.email = form.getEmail();
this.eduPersonPrincipalName = this.username + "@openaire.eu";
this.objectClass = Arrays.asList("inetOrgPerson", "eduPerson");
this.isNew = true;
}
public Name getDn() {
return dn;
}
public void setDn(Name dn) {
this.dn = dn;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getCommonName() {
return commonName;
}
public void setCommonName(String commonName) {
this.commonName = commonName;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getGivenName() {
return givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getEduPersonPrincipalName() {
return eduPersonPrincipalName;
}
public void setEduPersonPrincipalName(String eduPersonPrincipalName) {
this.eduPersonPrincipalName = eduPersonPrincipalName;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getOrganization() {
return organization;
}
public void setOrganization(String organization) {
this.organization = organization;
}
public String getStoredPassword() {
String[] byteValues = userPassword.split(",");
// Create a byte array of the same length
byte[] byteArray = new byte[byteValues.length];
// Convert each string value to a byte
for (int i = 0; i < byteValues.length; i++) {
byteArray[i] = Byte.parseByte(byteValues[i]);
}
// Convert byte array to a String (using UTF-8 or ASCII encoding)
return new String(byteArray);
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public List<String> getObjectClass() {
return objectClass;
}
public void setObjectClass(List<String> objectClass) {
this.objectClass = objectClass;
}
@Override
public Name getId() {
return this.getDn();
}
@Override
public boolean isNew() {
return this.isNew;
}
public void setNew(boolean isNew) {
this.isNew = isNew;
}
}

View File

@ -0,0 +1,64 @@
package eu.dnetlib.uoausermanagment.services;
import eu.dnetlib.uoausermanagment.configuration.Datasource;
import eu.dnetlib.uoausermanagment.configuration.GlobalVars;
import eu.dnetlib.uoausermanagment.configuration.Mail;
import eu.dnetlib.uoausermanagment.configuration.Properties;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class DeployService {
private final Datasource datasource;
private final String roleManagement;
private final Mail mail;
private final GlobalVars globalVars;
@Autowired
public DeployService(Properties properties, GlobalVars globalVars) {
this.datasource = properties.getDatasource();
this.roleManagement = properties.getRoleManagement();
this.mail = properties.getMail();
this.globalVars = globalVars;
}
@PostConstruct
public void checkProperties() {
if (datasource.getDriver() == null || datasource.getDriver().isEmpty()) {
throw new RuntimeException("user-management.datasource.driver is missing!");
} else if (datasource.getUrl() == null || datasource.getUrl().isEmpty()) {
throw new RuntimeException("user-management.datasource.url is missing!");
} else if (roleManagement == null || roleManagement.isEmpty()) {
throw new RuntimeException("user-management.role-management is missing!");
}
}
public Map<String, String> getProperties() {
Map<String, String> response = new HashMap<>();
response.put("user-management.datasource.driver", datasource.getDriver());
response.put("user-management.datasource.url", datasource.getUrl());
response.put("user-management.datasource.username", datasource.getUsername());
response.put("user-management.datasource.password", datasource.getPassword());
response.put("user-management.role-management", roleManagement);
response.put("user-management.mail.auth", mail.getAuth());
response.put("user-management.mail.sslProtocols", mail.getSslProtocols());
response.put("user-management.mail.from", mail.getFrom());
response.put("user-management.mail.host", mail.getHost());
response.put("user-management.mail.port", mail.getPort());
response.put("user-management.mail.username", mail.getUsername());
response.put("user-management.mail.password", mail.getPassword());
response.put("Date of deploy", 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,120 @@
package eu.dnetlib.uoausermanagment.services;
import eu.dnetlib.uoaauthorizationlibrary.authorization.exceptions.HttpException;
import eu.dnetlib.uoausermanagment.dto.StringResult;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.Map;
@Service
public class HttpService {
private static final Logger logger = LogManager.getLogger(HttpService.class);
private final RestTemplate restTemplate;
@Autowired
public HttpService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public <S> StringResult post(HttpServletRequest request, String path, S body, Map<String, String> params) {
return this.post(request, path, body, params, StringResult.class);
}
public <T, S> T post(HttpServletRequest request, String path, S body, Map<String, String> params, Class<T> responseType) {
String url = path + ((params != null) ? createParams(params) : "");
HttpHeaders headers = createHeaders(request);
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> httpEntity = new HttpEntity<>((body != null) ? body.toString() : "", headers);
try {
ResponseEntity<T> responseEntity = restTemplate.exchange(url, HttpMethod.POST, httpEntity, responseType);
if (responseEntity.getBody() != null) {
return responseEntity.getBody();
} else {
return null;
}
} catch (HttpClientErrorException e) {
logger.error("{}: {}", url, e.getMessage());
throw new HttpException(e.getMessage(), HttpStatus.resolve(e.getStatusCode().value()));
}
}
public <T, S> T put(HttpServletRequest request, String path, S body, Class<T> responseType) {
HttpHeaders headers = createHeaders(request);
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> httpEntity = new HttpEntity<>((body != null) ? body.toString() : "", headers);
try {
ResponseEntity<T> responseEntity = restTemplate.exchange(path, HttpMethod.PUT, httpEntity, responseType);
if (responseEntity.getBody() != null) {
return responseEntity.getBody();
} else {
return null;
}
} catch (HttpClientErrorException e) {
logger.error("{}: {}", path, e.getMessage());
throw new HttpException(e.getMessage(), HttpStatus.resolve(e.getStatusCode().value()));
}
}
public <T> T get(HttpServletRequest request, String path, Map<String, String> params, Class<T> responseType) {
String url = path + ((params != null) ? createParams(params) : "");
try {
return restTemplate.exchange
(url, HttpMethod.GET, new HttpEntity<>(createHeaders(request)), responseType).getBody();
} catch (HttpClientErrorException e) {
logger.error("{}: {}", url, e.getMessage());
throw new HttpException(e.getMessage(), HttpStatus.resolve(e.getStatusCode().value()));
}
}
public StringResult delete(HttpServletRequest request, String path, Map<String, String> params) {
return this.delete(request, path, params, StringResult.class);
}
public <T> T delete(HttpServletRequest request, String path, Map<String, String> params, Class<T> responseType) {
String url = path + ((params != null) ? createParams(params) : "");
try {
ResponseEntity<T> responseEntity = restTemplate.exchange
(url, HttpMethod.DELETE, new HttpEntity<>(createHeaders(request)), responseType);
if (responseEntity.getBody() != null) {
return responseEntity.getBody();
} else {
return null;
}
} catch (HttpClientErrorException e) {
logger.error("{}: {}", url, e.getMessage());
throw new HttpException(e.getMessage(), HttpStatus.resolve(e.getStatusCode().value()));
}
}
private String createParams(Map<String, String> params) {
StringBuilder ret = new StringBuilder("?");
int count = 0;
for (Map.Entry<String, String> param : params.entrySet()) {
ret.append(param.getKey()).append("=");
ret.append(param.getValue());
count++;
if (count != params.entrySet().size()) {
ret.append("&");
}
}
return ret.toString();
}
private HttpHeaders createHeaders(HttpServletRequest request) {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.set("Cookie", request.getHeader("Cookie"));
return headers;
}
}

View File

@ -0,0 +1,132 @@
package eu.dnetlib.uoausermanagment.services;
import eu.dnetlib.uoausermanagment.dao.UserRepository;
import eu.dnetlib.uoausermanagment.dao.ZombieUserRepository;
import eu.dnetlib.uoausermanagment.dto.form.RegisterForm;
import eu.dnetlib.uoausermanagment.entities.AccountStatus;
import eu.dnetlib.uoausermanagment.entities.User;
import eu.dnetlib.uoausermanagment.entities.ZombieUser;
import eu.dnetlib.uoausermanagment.utils.SSHAEncoder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
@Service
public class LDAPService {
private final Logger logger = LogManager.getLogger(LDAPService.class);
private final UserRepository userRepository;
private final ZombieUserRepository zombieUserRepository;
private final PasswordEncoder passwordEncoder = new SSHAEncoder();
@Autowired
public LDAPService(UserRepository userRepository, ZombieUserRepository zombieUserRepository) {
this.userRepository = userRepository;
this.zombieUserRepository = zombieUserRepository;
}
public boolean matchesPassword(CharSequence password, String encodedPassword) {
return passwordEncoder.matches(password, encodedPassword);
}
public AccountStatus accountStatus(String username) {
if(this.userRepository.findByUsername(username).isPresent()) {
return AccountStatus.ACTIVATED;
} else if(this.zombieUserRepository.findByUsername(username).isPresent()) {
return AccountStatus.ZOMBIE;
}
return AccountStatus.NOT_FOUND;
}
public AccountStatus accountStatusByEmail(String email) {
if(this.userRepository.findByEmail(email).isPresent()) {
return AccountStatus.ACTIVATED;
} else if(this.zombieUserRepository.findByEmail(email).isPresent()) {
return AccountStatus.ZOMBIE;
}
return AccountStatus.NOT_FOUND;
}
public boolean usernameExists(String username) {
return !this.accountStatus(username).equals(AccountStatus.NOT_FOUND);
}
public boolean emailExists(String email) {
return !this.accountStatusByEmail(email).equals(AccountStatus.NOT_FOUND); }
public User getUser(String username) {
return this.userRepository.findByUsername(username).orElse(null);
}
public User getUserByEmail(String email) {
return this.userRepository.findByEmail(email).orElse(null);
}
public ZombieUser getZombieUser(String username) {
return this.zombieUserRepository.findByUsername(username).orElse(null);
}
public ZombieUser getZombieUserByEmail(String email) {
return this.zombieUserRepository.findByEmail(email).orElse(null);
}
public String moveUser(String username) {
ZombieUser zombieUser = this.zombieUserRepository.findByUsername(username).orElse(null);
try {
if(zombieUser != null) {
User user = new User(zombieUser);
this.zombieUserRepository.delete(zombieUser);
this.userRepository.save(user);
return null;
}
return "User has not been found";
} catch (Exception e) {
logger.error(e.getMessage());
return "Something wrong happened. Please try again later.";
}
}
public String updateUserPassword(String username, String password) {
User user = this.userRepository.findByUsername(username).orElse(null);
try {
if (user != null) {
user.setUserPassword(passwordEncoder.encode(password));
user.setNew(false);
this.userRepository.save(user);
return null;
}
return "User has not been found";
} catch (Exception e) {
logger.error(e.getMessage());
return "Something wrong happened. Please try again later.";
}
}
public ZombieUser createZombieUser(RegisterForm form, Model model) {
try {
ZombieUser user = new ZombieUser(form);
user.setUserPassword(passwordEncoder.encode(form.getPassword()));
return this.zombieUserRepository.save(user);
} catch (Exception e) {
model.addAttribute("server_error", "LDAP error in creating user");
return null;
}
}
public String deleteUser(String username) {
if(this.accountStatus(username).equals(AccountStatus.ACTIVATED)) {
this.userRepository.delete(this.getUser(username));
return null;
} else if(this.accountStatus(username).equals(AccountStatus.ZOMBIE)) {
this.zombieUserRepository.delete(this.getZombieUser(username));
return null;
}
return "User has not been found";
}
}

View File

@ -0,0 +1,140 @@
package eu.dnetlib.uoausermanagment.services;
import eu.dnetlib.uoaauthorizationlibrary.authorization.security.AuthorizationService;
import eu.dnetlib.uoausermanagment.configuration.Properties;
import eu.dnetlib.uoausermanagment.dto.StringResult;
import eu.dnetlib.uoausermanagment.dto.UserDetails;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class RoleManagementService {
private static final Logger logger = LogManager.getLogger(RoleManagementService.class);
private final HttpService httpService;
private final String url;
private final AuthorizationService authorizationService;
private String mapType(String type, boolean communityMap) {
if (type.equals("organization")) {
type = "institution";
} else if (type.equals("ri") && communityMap) {
type = "community";
}
return type;
}
@Autowired
public RoleManagementService(HttpService httpService, Properties properties, AuthorizationService authorizationService) {
this.httpService = httpService;
this.url = properties.getRoleManagement();
this.authorizationService = authorizationService;
}
public StringResult assignMemberRole(String type, String id, HttpServletRequest request) throws HttpClientErrorException {
Map<String, String> params = new HashMap<>();
params.put("force", "true");
return this.httpService.post(request, url + "/member/" + mapType(type, false) + "/" + id, null, params);
}
public StringResult assignManagerRole(String type, String id, HttpServletRequest request) throws HttpClientErrorException {
Map<String, String> params = new HashMap<>();
params.put("force", "true");
return this.httpService.post(request, url + "/admin/" + mapType(type, true) + "/" + id, null, params);
}
public StringResult removeMemberRole(String type, String id, HttpServletRequest request) throws HttpClientErrorException {
Map<String, String> params = new HashMap<>();
params.put("force", "true");
return this.httpService.delete(request, url + "/member/" + mapType(type, false) + "/" + id, params);
}
public StringResult removeMemberRole(String type, String id, String email, HttpServletRequest request) throws HttpClientErrorException {
Map<String, String> params = new HashMap<>();
params.put("email", email);
return this.httpService.delete(request, url + "/member/" + mapType(type, false) + "/" + id, params);
}
public StringResult removeManagerRole(String type, String id, HttpServletRequest request) throws HttpClientErrorException {
return this.httpService.delete(request, url + "/admin/" + mapType(type, true) + "/" + id, null);
}
public StringResult removeManagerRole(String type, String id, String email, HttpServletRequest request) throws HttpClientErrorException {
Map<String, String> params = new HashMap<>();
params.put("email", email);
return this.httpService.delete(request, url + "/admin/" + mapType(type, true) + "/" + id, params);
}
public UserDetails[] getAllMembers(String type, String id, HttpServletRequest request) throws HttpClientErrorException {
return this.httpService.get(request, url + "/member/" + mapType(type, false) + "/" + id, null, UserDetails[].class);
}
public Integer getAllMembersCount(String type, String id, HttpServletRequest request) throws HttpClientErrorException {
return this.httpService.get(request, url + "/member/" + mapType(type, false) + "/" + id + "/count", null, Integer.class);
}
public UserDetails[] getAllManagers(String type, String id, HttpServletRequest request) throws HttpClientErrorException {
Map<String, String> params = new HashMap<>();
if(!authorizationService.isPortalAdmin() && !authorizationService.isCurator(type) && !authorizationService.isManager(type, id)) {
params.put("name", "false");
params.put("email", "false");
}
return this.httpService.get(request, url + "/admin/" + mapType(type, true) + "/" + id, params, UserDetails[].class);
}
public UserDetails[] getAllCurators(String type, HttpServletRequest request) throws HttpClientErrorException {
return this.httpService.get(request, url + "/curator/" + mapType(type, false), null, UserDetails[].class);
}
public boolean isMember(String type, String id, String email, HttpServletRequest request) throws HttpClientErrorException {
for (UserDetails userDetails : this.getAllMembers(type, id, request)) {
if (userDetails.getEmail().equalsIgnoreCase(email)) {
return true;
}
}
return false;
}
public boolean isManager(String type, String id, String email, HttpServletRequest request) throws HttpClientErrorException {
for (UserDetails userDetails : this.getAllManagers(type, id, request)) {
if (userDetails.getEmail().equalsIgnoreCase(email)) {
return true;
}
}
return false;
}
public List<StringResult> createMemberRole(String type, String id, HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
params.put("description", mapType(type, false) + " " + id);
String[] types = {type};
if(type.equals("ri") || type.equals("community")) {
types = new String[]{"ri", "community"};
}
return Arrays.stream(types).map(t -> this.httpService.post(request, url + "/member/" + mapType(t, false) + "/" + id + "/create", null, params)).toList();
}
public StringResult createCuratorRole(String type, HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
params.put("description", mapType(type, false) + " Curator");
return this.httpService.post(request, url + "/curator/" + mapType(type, false) + "/create", null, params);
}
public StringResult createRole(String name, String description, HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
params.put("name", name);
params.put("description", description);
return this.httpService.post(request, url + "/super/create", null, params);
}
}

View File

@ -0,0 +1,130 @@
package eu.dnetlib.uoausermanagment.services;
import eu.dnetlib.uoaauthorizationlibrary.authorization.exceptions.HttpException;
import eu.dnetlib.uoaauthorizationlibrary.authorization.exceptions.http.NotFoundException;
import eu.dnetlib.uoaauthorizationlibrary.authorization.security.AuthorizationService;
import eu.dnetlib.uoausermanagment.dao.RoleVerificationDAO;
import eu.dnetlib.uoausermanagment.dto.EmailDetails;
import eu.dnetlib.uoausermanagment.dto.Invitation;
import eu.dnetlib.uoausermanagment.entities.RoleVerification;
import eu.dnetlib.uoausermanagment.entities.VerificationType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Service("Verification")
public class RoleVerificationService {
private final RoleVerificationDAO dao;
private final AuthorizationService authorizationService;
private final UtilsService utilsService;
@Autowired
public RoleVerificationService(RoleVerificationDAO dao, AuthorizationService authorizationService, UtilsService utilsService) {
this.dao = dao;
this.authorizationService = authorizationService;
this.utilsService = utilsService;
}
private Invitation invite(EmailDetails details, String type, String id, VerificationType verificationType) {
Invitation invitation = new Invitation(this.dao.findByVerificationTypeAndTypeAndEntityAndEmail(verificationType, type, id, details.getEmail().getRecipient())
.orElse(this.dao.save(new RoleVerification(this.dao, details.getEmail().getRecipient(), verificationType, type, id))));
details.getEmail().replaceBody(details.getLink(), invitation);
this.utilsService.send(details.getEmail());
return invitation;
}
private boolean isMyVerification(String id, VerificationType verificationType) {
RoleVerification verification = this.dao.findByIdAndVerificationType(id, verificationType)
.orElseThrow(() -> new NotFoundException("Role verification with id: " + id + " has not been found for verification type: " + verificationType));
return this.authorizationService.getEmail().equalsIgnoreCase(verification.getEmail());
}
public List<String> getInvited(VerificationType verificationType, String type, String id) {
return this.dao.findByVerificationTypeAndTypeAndEntity(verificationType, type, id).stream().map(RoleVerification::getEmail).toList();
}
private void cancelInvitation(VerificationType verificationType, String type, String id, String email) {
String[] types = {type};
if(this.isCommunity(type)) {
types = new String[]{"community", "ri"};
}
this.cancelInvitation(verificationType, types, id, email);
}
private void cancelInvitation(VerificationType verificationType, String[] types, String id, String email) {
Arrays.stream(types).forEach(type -> this.dao.deleteByVerificationTypeAndTypeAndEntityAndEmail(verificationType, type, id, email));
}
public Invitation inviteMember(EmailDetails details, String type, String id) {
return this.invite(details, type, id, VerificationType.MEMBER);
}
public Invitation inviteManager(EmailDetails details, String type, String id) {
return this.invite(details, type, id, VerificationType.MANAGER);
}
public void cancelAllInvitation(String type, String id, String email) {
this.cancelInvitation(VerificationType.MANAGER, type, id, email);
this.cancelInvitation(VerificationType.MEMBER, type, id, email);
}
public void cancelManagerInvitation(String type, String id, String email) {
this.cancelInvitation(VerificationType.MANAGER, type, id, email);
}
public void cancelMemberInvitation(String type, String id, String email) {
this.cancelInvitation(VerificationType.MEMBER, type, id, email);
}
public List<String> getInvitedManagers(String type, String id) {
return this.getInvited(VerificationType.MANAGER, type, id);
}
public List<String> getInvitedMembers(String type, String id) {
return this.getInvited(VerificationType.MEMBER, type, id);
}
public RoleVerification getRoleVerification(String id) {
return this.dao.findById(id).orElseThrow(() -> new NotFoundException("Role verification with id: " + id + " has not been found"));
}
public void verify(String id, String code) {
this.dao.findByIdAndVerificationCode(id, code).
orElseThrow(() -> new HttpException("Role verification with id: " + id + " and code " + code + " has not been found", HttpStatus.BAD_REQUEST));
}
public boolean isMyManagerVerification(String id) {
return this.isMyVerification(id, VerificationType.MANAGER);
}
public boolean isMyMemberVerification(String id) {
return this.isMyVerification(id, VerificationType.MEMBER);
}
public boolean isMyVerification(String id) {
RoleVerification verification = this.getRoleVerification(id);
return this.authorizationService.getEmail().equalsIgnoreCase(verification.getEmail());
}
public void deleteVerification(String id) {
RoleVerification verification = this.getRoleVerification(id);
this.dao.delete(verification);
}
public String getRoleFromVerification(String id) {
RoleVerification verification = this.getRoleVerification(id);
if(verification.getVerificationType().equals(VerificationType.MANAGER)) {
return this.authorizationService.manager(verification.getType(), verification.getEntity());
} else {
return this.authorizationService.member(verification.getType(), verification.getEntity());
}
}
public boolean isCommunity(String type) {
return type.equalsIgnoreCase("community") || type.equalsIgnoreCase("ri");
}
}

View File

@ -0,0 +1,133 @@
package eu.dnetlib.uoausermanagment.services;
import eu.dnetlib.uoaauthorizationlibrary.authorization.exceptions.HttpException;
import eu.dnetlib.uoausermanagment.dao.UserVerificationDAO;
import eu.dnetlib.uoausermanagment.dto.Email;
import eu.dnetlib.uoausermanagment.entities.UserVerification;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
@Service
public class UserVerificationService {
private final UserVerificationDAO dao;
private final UtilsService utilsService;
@Autowired
public UserVerificationService(UserVerificationDAO dao, UtilsService utilsService) {
this.dao = dao;
this.utilsService = utilsService;
}
public UserVerification create(String username) {
UserVerification verification = this.dao.findByUsername(username).orElse(new UserVerification(username));
verification.updateVerificationCode();
return this.dao.save(verification);
}
public String validate(HttpServletRequest request, Model model, String username, String verificationCode, String path) {
UserVerification verification = this.dao.findByUsernameAndVerificationCode(username, verificationCode).orElse(null);
if(verification == null) {
model.addAttribute("server_error", "Username or verification code are not valid.");
return path;
} else if(verification.expired()) {
request.getSession().setAttribute("expired", true);
return "redirect:/expired";
}
this.dao.delete(verification);
return null;
}
public String createURL(HttpServletRequest request, String path, String params) {
return request.getScheme() + "://" + request.getServerName() + (request.getServerPort() != 80 ? (":" + request.getServerPort()):"")
+ request.getContextPath() + "/" + path + params;
}
public void sendActivationVerification(HttpServletRequest request, Model model, UserVerification verification, String userEmail) {
String url = createURL(request,"activate", "?code=" + verification.getVerificationCode());
Email email = new Email();
email.setBody("<p>Hello " + verification.getUsername() + ",</p>" +
"<p> A request has been made to verify your email and activate your OpenAIRE account. To activate your " +
"account, you will need to submit your username and this activation code in order to verify that the " +
"request was legitimate.</p>" +
"<p>" +
"The activation code is " + verification.getVerificationCode() +
"</p>" +
"Click the URL below and proceed with activating your password." +
"<p><a href=" + url + ">" + url + "</a></p>" +
"<p>The activation code is valid for 24 hours.</p>" +
"<p>Thank you,</p>" +
"<p>OpenAIRE technical team</p>");
email.setSubject("Activate your OpenAIRE account");
email.setRecipient(userEmail);
try {
this.utilsService.send(email);
} catch (HttpException e) {
model.addAttribute("server_error", "Email sent failed");
}
}
public void sendVerificationToDelete(HttpServletRequest request, Model model, UserVerification verification, String userEmail) {
String url = createURL(request,"delete-account", "?code=" + verification.getVerificationCode());
Email email = new Email();
email.setBody("<p>Hello " + verification.getUsername() + ",</p>" +
"<p> A request has been made to get a verification code to delete your OpenAIRE account. To delete your " +
"account, you will need to submit your username and this verification code in order to verify that the " +
"request was legitimate.</p>" +
"<p>" +
"The verification code is " + verification.getVerificationCode() +
"</p>" +
"Click the URL below and proceed with deleting your account." +
"<p><a href=" + url + ">" + url + "</a></p>" +
"<p>The verification code is valid for 24 hours.</p>" +
"<p>Thank you,</p>" +
"<p>OpenAIRE technical team</p>");
email.setSubject("Request to delete your OpenAIRE account");
email.setRecipient(userEmail);
try {
this.utilsService.send(email);
} catch (HttpException e) {
model.addAttribute("server_error", "Email sent failed");
}
}
public void sendUsernameReminder(Model model, UserVerification verification, String userEmail) {
Email email = new Email();
email.setBody("<p>Hello,</p>" +
"<p> A username reminder has been requested for your OpenAIRE account.</p>" +
"<p> Your username is <b>" + verification.getUsername() + "</b>.</p>" +
"<p> Thank you, </p>" +
"<p> OpenAIRE technical team</p>");
email.setSubject("Your OpenAIRE username");
email.setRecipient(userEmail);
try {
this.utilsService.send(email);
} catch (HttpException e) {
model.addAttribute("server_error", "Email sent failed");
}
}
public void sendForgotPasswordVerification(HttpServletRequest request, Model model, UserVerification verification, String userEmail) {
String url = createURL(request,"verify", "?code=" + verification.getVerificationCode());
Email email = new Email();
email.setBody("<p>Hello,</p>" +
"<p> A request has been made to reset your OpenAIRE account password. To reset your " +
"password, you will need to submit this verification code in order to verify that the " +
"request was legitimate.</p>" +
"<p> The verification code is " + verification.getVerificationCode() + "</p>" +
"Click the URL below and proceed with verification." +
"<p><a href=" + url + ">" + url + "</a></p>" +
"<p>The verification code is valid for 24 hours.</p>" +
"<p>Thank you,</p>" +
"<p>OpenAIRE technical team</p>");
email.setSubject("Your OpenAIRE password reset request");
email.setRecipient(userEmail);
try {
this.utilsService.send(email);
} catch (HttpException e) {
model.addAttribute("server_error", "Email sent failed");
}
}
}

View File

@ -0,0 +1,82 @@
package eu.dnetlib.uoausermanagment.services;
import eu.dnetlib.uoaauthorizationlibrary.authorization.exceptions.HttpException;
import eu.dnetlib.uoausermanagment.configuration.Google;
import eu.dnetlib.uoausermanagment.configuration.Mail;
import eu.dnetlib.uoausermanagment.configuration.Properties;
import eu.dnetlib.uoausermanagment.dto.Email;
import eu.dnetlib.uoausermanagment.dto.GoogleResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
@Service
public class UtilsService {
private static final Logger logger = LogManager.getLogger(UtilsService.class);
private static final Pattern RESPONSE_PATTERN = Pattern.compile("[A-Za-z0-9_-]+");
private final JavaMailSender mailSender;
private final Mail mail;
private final Google google;
private final RestTemplate restTemplate;
@Autowired
public UtilsService(JavaMailSender mailSender, Properties properties, RestTemplate restTemplate) {
this.mailSender = mailSender;
this.mail = properties.getMail();
this.google = properties.getGoogle();
this.restTemplate = restTemplate;
}
public void send(Email email) {
logger.debug("Try to connect to mail sender with {}", mail.getUsername());
try {
logger.debug("Try to sent e-mail to {}\nSubject: {}\nBody:{}", email.getRecipient(), email.getSubject(), email.getBody());
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(new InternetAddress(mail.getFrom()));
List<String> bccRecipients = new ArrayList<>(Collections.singletonList(mail.getFrom()));
helper.setTo(email.getRecipient());
helper.setBcc(bccRecipients.toArray(new String[0]));
helper.setSubject(email.getSubject());
helper.setText(email.getBody(), true);
mailSender.send(message);
logger.debug("Sent message successfully....\n");
} catch (Exception e) {
throw new HttpException(e.getMessage(), HttpStatus.BAD_REQUEST);
}
}
public boolean processResponse(String response) {
if (!responseSanityCheck(response)) {
throw new RuntimeException("Response contains invalid characters");
}
URI verifyUri = URI.create(String.format("https://www.google.com/recaptcha/api/siteverify?secret=%s&response=%s", google.getSecret(), response));
GoogleResponse googleResponse = restTemplate.getForObject(verifyUri, GoogleResponse.class);
assert googleResponse != null;
if (!googleResponse.isSuccess()) {
logger.error("Has client error: {}", googleResponse.hasClientError());
throw new RuntimeException("ReCaptcha was not successfully validated");
}
return googleResponse.isSuccess();
}
private boolean responseSanityCheck(String response) {
return StringUtils.hasLength(response) && RESPONSE_PATTERN.matcher(response).matches();
}
}

View File

@ -0,0 +1,119 @@
package eu.dnetlib.uoausermanagment.services;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ValidationService {
public static String VALID_PASSWORD = "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=\\S+$).{6,}$";
public static String SPACE = "/[\\s]+/g";
public static String LOWER_CASE_LETTERS = "/[a-z]/g";
public static String UPPER_CASE_LETTERS = "/[A-Z]/g";
public static String NUMBERS = "/[0-9]/g";
public static String VALID_EMAIL = "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$";
public static String VALID_USERNAME = "^[a-zA-Z0-9][a-zA-Z0-9._\\-]{4,150}";
public static String STARTS_WITH = "^[a-zA-Z0-9].*";
public static String ALLOWED_CHARS = "^[a-zA-Z0-9._\\-]";
private final UtilsService service;
@Autowired
public ValidationService(UtilsService service) {
this.service = service;
}
public String validateRequired(String input, String error) {
if (input == null || input.isEmpty()) {
return error;
} else {
return null;
}
}
public String validateEmail(String email) {
return validateEmail(email, null, false);
}
public String validateEmail(String email, String emailConfirmation) {
return validateEmail(email, emailConfirmation, true);
}
private String validateEmail(String email, String emailConfirmation, boolean withConfirmation) {
if (email.isEmpty()) {
return "Please enter your email.";
} else if (email.matches(VALID_EMAIL)) {
return withConfirmation && !email.equalsIgnoreCase(emailConfirmation) ? "The emails don't match." : null;
} else {
return "Please enter a valid email.";
}
}
public String validateUsername(String username) {
if (username.matches(VALID_USERNAME)) {
return null;
} else {
if (containsLessCharsThan(5, username)) {
return "Minimum username length 5 characters.";
} else if (containsMoreCharsThan(150, username)) {
return "Maximum username length 150 characters.";
} else if (containsOnlyAllowedChars(username)) {
return "You can use letters, numbers, underscores, hyphens and periods.";
} else if (startsWithLetterOrDigit(username)) {
return "The username must start with letter or digit.";
}
return "Please enter your username";
}
}
public String validatePassword(String password) {
return this.validatePassword(password, null, false);
}
public String validatePassword(String password, String passwordConfirmation) {
return this.validatePassword(password, passwordConfirmation, true);
}
private String validatePassword(String password, String passwordConfirmation, boolean withConfirmation) {
if (password.matches(VALID_PASSWORD)) {
return withConfirmation && !password.equals(passwordConfirmation) ? "The passwords don't match." : null;
} else {
if (password.matches(SPACE)) {
return "No white space allowed.";
}
if (!password.matches(LOWER_CASE_LETTERS)) {
return "Please add a lowercase letter.";
}
if (password.matches(UPPER_CASE_LETTERS)) {
return "Please add a uppercase letter.";
}
if (password.matches(NUMBERS)) {
return "Please add a number.";
} else if (containsLessCharsThan(6, password)) {
return "Minimum username length 6 characters.";
}
return "Please enter your password";
}
}
public String validateRecaptcha(String recaptchaResponse) {
return !this.service.processResponse(recaptchaResponse)?"You missed the reCAPTCHA validation":null;
}
private boolean startsWithLetterOrDigit(String username) {
return username.matches(STARTS_WITH);
}
private boolean containsOnlyAllowedChars(String username) {
return username.matches(ALLOWED_CHARS);
}
private boolean containsLessCharsThan(int count, String input) {
return input.length() < count;
}
private boolean containsMoreCharsThan(int count, String input) {
return input.length() > count;
}
}

View File

@ -0,0 +1,55 @@
package eu.dnetlib.uoausermanagment.utils;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
public class SSHAEncoder implements PasswordEncoder {
private static final int SALT_LENGTH = 4;
@Override
public String encode(CharSequence rawPassword) {
try {
// Generate a random salt
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
// Compute the SHA-1 hash of the password concatenated with the salt
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update(rawPassword.toString().getBytes(StandardCharsets.UTF_8));
sha1.update(salt);
byte[] hashedBytes = sha1.digest();
// Concatenate the hash and the salt
byte[] hashWithSalt = new byte[hashedBytes.length + salt.length];
System.arraycopy(hashedBytes, 0, hashWithSalt, 0, hashedBytes.length);
System.arraycopy(salt, 0, hashWithSalt, hashedBytes.length, salt.length);
// Base64-encode the hash and salt, and prefix with "{SSHA}"
return "{SSHA}" + Base64.getEncoder().encodeToString(hashWithSalt);
} catch (Exception e) {
throw new RuntimeException("Error encoding password", e);
}
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
try {
byte[] decodedBytes = Base64.getDecoder().decode(encodedPassword.substring(6));
byte[] salt = Arrays.copyOfRange(decodedBytes, 20, decodedBytes.length);
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(rawPassword.toString().getBytes(StandardCharsets.UTF_8));
md.update(salt);
byte[] hashedBytes = md.digest();
return MessageDigest.isEqual(hashedBytes, Arrays.copyOfRange(decodedBytes, 0, 20));
} catch (Exception e) {
throw new RuntimeException("Error matching password", e);
}
}
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="30">
<Properties>
<Property name="LOG_PATTERN">
%d %p %t [%c] - %m%n
</Property>
</Properties>
<Appenders>
<!-- Rolling File Appender -->
<RollingFile name="R" fileName="/var/log/dnet/uoa-user-management/uoa-user-management.log"
filePattern="/var/log/dnet/uoa-user-management/uoa-user-management-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<RollingFile name="S" fileName="/var/log/dnet/uoa-user-management/uoa-user-management-spring.log"
filePattern="/var/log/dnet/uoa-user-management/uoa-user-management-spring-%d{yyyy-MM-dd}-%i.log">
<PatternLayout>
<Pattern>${LOG_PATTERN}</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="10MB" />
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="eu.dnetlib" level="debug" additivity="false">
<AppenderRef ref="R"/>
</Logger>
<Root level="info">
<AppenderRef ref="S"/>
</Root>
</Loggers>
</Configuration>

Some files were not shown because too many files have changed in this diff Show More